openai / openai/codex-security

Canonical code-evidence paths bypass repository-relative path validation

Open
#541 0 comments 0 reactions 0 assignees View on GitHub

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.ts explicitly runs every locations[].path through safeRelativePath();
  • findings.schema.json defines codeEvidence[].path as 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 an id and nonempty code before later schema validation.

A deterministic sealed-contract reproduction is:

  1. copy the bundled completed-scan example;
  2. add otherwise valid codeEvidence to a finding with path: "../../outside.ts";
  3. update the sealed findings.json digest in scan-manifest.json;
  4. 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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.