{"id":"CVE-2026-49988","revision":null,"records":[{"revision":"fc54ac13b02f4d0ca11ad70daa559c59","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-49988","aliases":[],"title":"Repomix: attach_packed_output can bypass file-read secret scanning for supported local files","description":"Repomix is a tool that packs repositories into AI-friendly files. Prior to 1.14.1, the Repomix MCP server attach_packed_output and read_repomix_output flow can register and read arbitrary local .json, .txt, .md, or .xml files without the file_system_read_file runSecretLint() safety check or Repomix packed-output validation, allowing MCP callers to bypass the local file-read secret-scanning boundary. This issue is fixed in version 1.14.1.","state":0,"publishedAt":"2026-07-15T18:05:10.789+00:00","modifiedAt":"2026-07-18T01:16:12.325+00:00","affected":[{"ecosystem":"Vendor product","name":"repomix","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"yamadashy\",\n                    \"product\": \"repomix\",\n                    \"versions\": [\n                        {\n                            \"version\": \"< 1.14.1\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 4.0","vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N","score":6.8,"severity":"MEDIUM"}],"references":["https://github.com/yamadashy/repomix/security/advisories/GHSA-hwpp-h97w-2h3j","https://github.com/yamadashy/repomix/commit/e447f7dba6f51fdb26bcad0c280542fca291960e","https://github.com/yamadashy/repomix/releases/tag/v1.14.1"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-49988","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-49988","identifiers":["CVE-2026-49988"]},"retained":false,"historicalAffected":[]},{"revision":"31c1be5f21624ed9bfcb1b3e704883dc","observedAt":"2026-10-25T12:17:38.331+00:00","statement":{"source":"nvd","id":"CVE-2026-49988","aliases":[],"title":"Repomix is a tool that packs repositories into AI-friendly files. Prior to 1.14.1, the Repomix MCP server attach_packed_output and read_repomix_output flow can register and read arbitrary local .json, .txt, .md, or .xml files without the fi…","description":"Repomix is a tool that packs repositories into AI-friendly files. Prior to 1.14.1, the Repomix MCP server attach_packed_output and read_repomix_output flow can register and read arbitrary local .json, .txt, .md, or .xml files without the file_system_read_file runSecretLint() safety check or Repomix packed-output validation, allowing MCP callers to bypass the local file-read secret-scanning boundary. This issue is fixed in version 1.14.1.","state":0,"publishedAt":"2026-07-15T19:17:25.823+00:00","modifiedAt":"2026-10-24T21:10:00.13+00:00","affected":[],"metrics":[{"system":"CVSS 4.0 · security-advisories@github.com · Secondary","vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:L/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X","score":6.8,"severity":"MEDIUM"},{"system":"CVSS 3.1 · nvd@nist.gov · Primary","vector":"CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:N","score":5.5,"severity":"MEDIUM"}],"references":["https://github.com/yamadashy/repomix/commit/e447f7dba6f51fdb26bcad0c280542fca291960e","https://github.com/yamadashy/repomix/releases/tag/v1.14.1","https://github.com/yamadashy/repomix/security/advisories/GHSA-hwpp-h97w-2h3j"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-49988","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Analyzed","weaknesses":["CWE-200"],"productCriteria":["cpe:2.3:a:yamadashy:repomix:*:*:*:*:*:*:*:*"],"sourceDates":{"published":"2026-07-15T19:17:25.823","lastModified":"2026-10-24T21:10:00.130"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-49988","identifiers":["CVE-2026-49988"]},"retained":false,"historicalAffected":[]},{"revision":"4030a7bac3964103b05c7825598ecc3b","observedAt":"2026-10-24T13:17:17.793+00:00","statement":{"source":"osv","id":"GHSA-hwpp-h97w-2h3j","aliases":["CVE-2026-49988"],"title":"repomix: attach_packed_output can bypass file-read secret scanning for supported local files","description":"# `attach_packed_output` can register arbitrary `.json/.txt/.md/.xml` files and bypass the MCP file-read safety check\n\n## Summary\n\nRepomix's MCP server exposes a normal `file_system_read_file` tool that reads absolute paths only after running the project's secret check. However, the `attach_packed_output` plus `read_repomix_output` flow can read arbitrary local `.json`, `.txt`, `.md`, or `.xml` files without the same safety check and without verifying that the file is actually a Repomix packed output.\n\nThis is a medium-severity local MCP file-read boundary issue. The affected deployment is the documented `repomix --mcp` stdio server used by AI assistants. A prompt or lower-trust model action that can invoke MCP tools can use `attach_packed_output` on a local JSON/text file, receive an `outputId`, then call `read_repomix_output` to retrieve the full file content.\n\n## Affected target\n\n- Repository: `yamadashy/repomix`\n- Commit reviewed: `adf5a12f2211a7fabf24ee11a21734adccee5143`\n- Component: MCP server tools\n- Package version reviewed: `repomix@1.14.0`\n\n## Root cause\n\nThe file-read safety boundary is implemented per tool rather than per local-file capability. `file_system_read_file` reads the file and runs `runSecretLint()` before returning content. `attach_packed_output` reads and registers local files through a separate path, but only checks file extension and parsing format. It does not verify a Repomix output header/schema and does not run the secret check before registering the path.\n\n## Vulnerability chain\n\n1. `attach_packed_output` accepts a direct file path, not only a directory.\n2. `resolveOutputFilePath()` allows any file whose extension matches `.xml`, `.md`, `.txt`, or `.json`.\n3. The tool reads that file with `fs.readFile(outputFilePath, 'utf8')`.\n4. It extracts metrics, but malformed or non-Repomix JSON simply produces empty metrics rather than rejection.\n5. `formatPackToolResponse()` registers the original file path under a generated `outputId`.\n6. `read_repomix_output` resolves the `outputId` and returns the full file content.\n\n## Auth boundary violated\n\nThe respected boundary is the explicit local file-read guard: `file_system_read_file` blocks files that fail the secret scan.\n\nThe ignored boundary is the alternate packed-output path. A caller can register a supported-extension file as an output and read it through `read_repomix_output` without passing through `runSecretLint()` or a packed-output validation step.\n\n## Source trace\n\n- `src/mcp/tools/fileSystemReadFileTool.ts:72-83`: direct file reads run `runSecretLint()` and return an error if the scan finds sensitive content.\n- `src/mcp/tools/attachPackedOutputTool.ts:76-87`: direct file input is accepted based only on extension.\n- `src/mcp/tools/attachPackedOutputTool.ts:111-120`: `.json`, `.txt`, `.md`, and `.xml` are supported formats.\n- `src/mcp/tools/attachPackedOutputTool.ts:228-240`: JSON parse errors return empty metrics rather than rejecting the file as non-Repomix output.\n- `src/mcp/tools/attachPackedOutputTool.ts:272-308`: the file is read and passed to `formatPackToolResponse()` without a secret check.\n- `src/mcp/tools/mcpToolRuntime.ts:77-82`: `formatPackToolResponse()` registers the provided `outputFilePath` and reads it.\n- `src/mcp/tools/readRepomixOutputTool.ts:56-74`: `read_repomix_output` reads the registered file path and returns its content.\n- `README.md:984-991`: the tool is documented as providing secure access to existing packed outputs.\n\n## Reproduction\n\n`run.sh`:\n\n```bash\n#!/usr/bin/env bash\nset -euo pipefail\nset +e\nnode run.js 2>&1 | tee transcript.txt\nrc=${PIPESTATUS[0]}\nset -e\nprintf '%s\\n' \"$rc\" > exit-code.txt\nexit \"$rc\"\n```\n\nThe harness creates a temporary `credentials.json` containing a sentinel value, follows the `attach_packed_output` path for supported-extension files, registers the file path under an output ID, and then reads it back through the `read_repomix_output` path. It also checks the source-code contrast between the guarded direct file-read tool and the unguarded attach path.\n\nObserved transcript:\n\n```text\nATTACH_TOOL_SOURCE_READS_FILE=true\nATTACH_TOOL_HAS_SECRETLINT_CHECK=false\nREAD_FILE_TOOL_HAS_SECRETLINT_CHECK=true\nRUNTIME_REGISTERS_OUTPUT_PATH=true\nATTACH_ACCEPTS_JSON_EXTENSION=true\nATTACHED_NON_REPOMIX_JSON_PATH=true\nSENTINEL_READ_BACK=true\nREPOMIX_ATTACH_PACKED_OUTPUT_ARBITRARY_JSON_READ_REPRODUCED=true\n```\n\n## Impact\n\nIn the MCP threat model, an assistant/tool caller can read local JSON/text/Markdown/XML files through a path that bypasses the file-read tool's secret scanning. Examples include project configuration JSON, exported tokens, local tool settings, or other plaintext files with supported extensions.\n\nThis does not require shell execution or writing files. It requires MCP tool-call capability against a Repomix server running with local filesystem access.\n\n## Suggested fix\n\nApply the same safety boundary to all local-file read paths:\n\n- Require `attach_packed_output` to validate that the target file is a genuine Repomix output before registration.\n- Reject malformed/non-Repomix JSON/XML/Markdown/plain files instead of registering them with empty metrics.\n- Run the same secret check used by `file_system_read_file` before registering or returning content.\n- Consider storing a content snapshot in the registry rather than registering arbitrary local paths for later reads.","state":0,"publishedAt":"2026-07-01T19:01:41+00:00","modifiedAt":"2026-07-01T19:26:31.183821+00:00","affected":[{"ecosystem":"npm","name":"repomix","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0"},{"kind":"fixed","version":"1.14.1"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V4","vector":"CVSS:4.0/AV:L/AC:L/AT:N/PR:N/UI:N/VC:H/VI:N/VA:N/SC:N/SI:N/SA:N","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"MODERATE"}],"references":["https://github.com/yamadashy/repomix/security/advisories/GHSA-hwpp-h97w-2h3j","https://github.com/yamadashy/repomix"],"sourceUrl":"https://github.com/advisories/GHSA-hwpp-h97w-2h3j","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-hwpp-h97w-2h3j","identifiers":["GHSA-hwpp-h97w-2h3j","CVE-2026-49988"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-10-27T04:23:20.6482565+00:00","complete":true,"records":1758,"lastAttemptAt":"2026-10-27T04:23:20.6482565+00:00","lastSuccessAt":"2026-10-27T04:23:21.0403366+00:00","error":null,"lastVerifiedAt":"2026-10-27T04:23:21.0403386+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-187d2b72c94ceb8c4417f1032ec3109a3a3a7b730abadb561d8cdd2a96e04d27-44adb5fc4ec2447b4a14a9a186d21f635f5ab0fe59c9ca03fbd7387196ed1b95","complete":true,"records":414861,"lastAttemptAt":"2026-10-27T04:23:19.4839227+00:00","lastSuccessAt":"2026-10-27T04:23:19.4592214+00:00","error":null,"lastVerifiedAt":"2026-10-27T04:23:19.4839227+00:00","snapshotPublishedAt":"2026-10-27T03:23:47+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-43321610382942b8ad8c85917eab1546","complete":false,"records":4735,"lastAttemptAt":"2026-10-27T04:24:29.5120624+00:00","lastSuccessAt":"2026-10-24T23:18:49.862+00:00","error":"InvalidDataException","lastVerifiedAt":"2026-10-24T23:18:49.862+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":0,"expectedIdentifiers":13477},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-10-27T04:23:20.6482565+00:00","complete":true,"records":1093,"lastAttemptAt":"2026-10-27T04:23:20.6482565+00:00","lastSuccessAt":"2026-10-27T04:23:21.0415276+00:00","error":null,"lastVerifiedAt":"2026-10-27T04:23:21.0415281+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-1e75823a9a3a4b74973abff44e356610","complete":false,"records":13416,"lastAttemptAt":"2026-10-27T04:24:27.4557647+00:00","lastSuccessAt":"2026-10-27T04:24:27.452+00:00","error":null,"lastVerifiedAt":"2026-10-27T04:24:27.452+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13077,"expectedIdentifiers":13477},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-c3121b113ecd88f1c92ccfa0ec9757ddc8386e4c12afd2597450b815744f800a","complete":true,"records":9779,"lastAttemptAt":"2026-10-27T04:23:20.1429206+00:00","lastSuccessAt":"2026-10-26T15:37:14.3083004+00:00","error":null,"lastVerifiedAt":"2026-10-27T04:23:20.1429206+00:00","snapshotPublishedAt":"2026-10-26T14:48:41+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-bad5d31e7f6a5e3d338e11d8789069b63620a403f927730769688b42f768e4f6","complete":true,"records":1965,"lastAttemptAt":"2026-10-27T04:23:19.6550338+00:00","lastSuccessAt":"2026-10-26T16:35:43.1460623+00:00","error":null,"lastVerifiedAt":"2026-10-27T04:23:19.6550338+00:00","snapshotPublishedAt":"2026-10-26T16:18:29+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-a393d8fe0ae8408f3e4cab413b76047090c8e4a3c0a186c79edf33c9a3d3af95","complete":true,"records":2995,"lastAttemptAt":"2026-10-27T04:23:20.5252815+00:00","lastSuccessAt":"2026-10-26T14:35:47.9640893+00:00","error":null,"lastVerifiedAt":"2026-10-27T04:23:20.5252815+00:00","snapshotPublishedAt":"2026-10-26T14:18:55+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-2c2579bb03487537529e2b647fd2d9950cfc0fec1a9832dba33e322b8dcbe369","complete":true,"records":230812,"lastAttemptAt":"2026-10-27T04:23:20.0379863+00:00","lastSuccessAt":"2026-10-26T21:37:26.5810298+00:00","error":null,"lastVerifiedAt":"2026-10-27T04:23:20.0379863+00:00","snapshotPublishedAt":"2026-10-26T21:33:12+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null}]}