openai / openai/codex-security
Canonical code-evidence paths bypass repository-relative path validation
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 10.8k
- Forks
- 801
- Avg merge
- 1d 8h
- Merged PRs (30d)
- 257
Description
Summary
Canonical finding locations are required to use safe repository-relative POSIX paths, but codeEvidence[].path is only constrained to a nonempty string.
A sealed finding can therefore claim source-code evidence at an absolute, traversal, Windows-style, or colon-bearing path even though the same path would be rejected in locations[].path.
Reproduction / evidence
Current upstream main at 37bf87a692fc72d41f7312cc48808d699d204fba has two different validation paths:
contract.tsexplicitly runs everylocations[].paththroughsafeRelativePath();findings.schema.jsondefinescodeEvidence[].pathas only{ "type": "string", "minLength": 1 };- the Python finalizer's
_validate_finding()validates each ordinary location with_validate_location(), but for code evidence it only requires anidand nonemptycodebefore later schema validation.
A deterministic sealed-contract reproduction is:
- copy the bundled completed-scan example;
- add otherwise valid
codeEvidenceto a finding withpath: "../../outside.ts"; - update the sealed
findings.jsondigest inscan-manifest.json; - call
loadContract().
On current main, the traversal path satisfies the findings schema and no canonical code-evidence path check rejects it.
Expected behavior: canonical codeEvidence[].path should obey the same repository-relative safety boundary as source locations and artifact paths.
Root cause
The path-safety rule was implemented for locations in code, while the optional code-evidence path was added to the schema without an equivalent path constraint. Because the shared schema is consumed by both the TypeScript loader and Python finalizer, the omission exists on both validation surfaces.
Suggested fix
Add the canonical safe-path pattern to codeEvidence[].path, rejecting:
- absolute paths;
..traversal segments;- backslashes / Windows-style paths;
- colon-bearing path components;
- the standalone
.path; - NUL characters.
Add a focused sealed-contract regression that reseals the fixture after inserting ../../outside.ts and requires loadContract() to reject it.
Impact
This does not provide arbitrary file reads by itself because codeEvidence.code is already embedded in the finding. It is an integrity issue: a sealed Codex Security finding can currently attribute canonical source evidence to a path outside the repository/path model that the rest of the contract enforces, and downstream report/publication adapters can present that misleading path as evidence.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with contract.ts and findings.schema.json, then trace the Python finalizer's _validate_finding() path and loadContract() using the bundled completed-scan example. Reseal the fixture after adding ../../outside.ts to codeEvidence.path and verify the sealed-contract regression rejects it, along with the other unsafe path forms described in the issue.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, typescript
- Domain
- security, tooling
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 72/100