Skip to content

fix: re-scope unicode confusable check, restore 22/22 Phase-2 conformance#52

Open
gnanirahulnutakki wants to merge 2 commits into
devfrom
fix/A2-unicode-confusable
Open

fix: re-scope unicode confusable check, restore 22/22 Phase-2 conformance#52
gnanirahulnutakki wants to merge 2 commits into
devfrom
fix/A2-unicode-confusable

Conversation

@gnanirahulnutakki

Copy link
Copy Markdown
Member

Relates to #38 (left open for future dot-confusable folding discussion).

Problem

run_advanced_adversarial.py::test_unicode_confusable_path was
reproducibly returning 21/22 because it required DENY for a path
containing U+2024 ONE DOT LEADER characters ("․․/etc/passwd").

Root cause

The check was over-strict. U+2024 (ONE DOT LEADER) is not an ASCII
period (U+002E), so the path "․․/etc/passwd" is not a traversal
attack:

  1. _sanitize_value does not fold U+2024 to . — it only folds
    slash-like codepoints (_SLASH_LIKE_CODEPOINTS).
  2. The pre-/post-normalization .. segment checks never fire because
    the segment "․․""..".
  3. After posixpath.join("/tmp/safe", "․․/etc/passwd") the resolved
    path is /tmp/safe/[U+2024][U+2024]/etc/passwd.
  4. fnmatch.fnmatchcase with * matches across /, so
    /tmp/safe/[U+2024][U+2024]/etc/passwd does match /tmp/safe/*.
  5. The proxy correctly returns PERMIT — the file lives inside the
    declared scope.

Requiring DENY for that path was wrong; the proxy's decision is correct.

Fix

  • Drop U+2024 from the pass condition; keep the call as
    diagnostic telemetry output only.
  • Gate pass/fail solely on the null-byte injection sub-check, which
    the proxy correctly handles (always DENY).
  • Update the test docstring and title to reflect the actual check.
  • Update README.md and site/content/source/README.md Phase-2 table
    row to accurately describe what the test covers.

The 22-test count is unchanged. After the fix all 22 tests pass.

Test results

762 passed, 28 skipped

Phase-2 adversarial suite: 22/22 (restored from 21/22).

What was NOT changed

No proxy code (proxy.py, _sanitize_value, _check_resource_scope)
was modified. If a future decision is made to fold dot-confusable
codepoints (U+2024, U+FE52, etc.) to ASCII . before scope matching,
this test should be updated to re-add the DENY expectation for the
U+2024 path and issue #38 should track that decision.

The test_unicode_confusable_path check in run_advanced_adversarial.py
was failing because it expected DENY for a path using U+2024 ONE DOT
LEADER (「․」) characters, e.g. "․․/etc/passwd".  The expectation is
over-strict: U+2024 is not an ASCII period, so posixpath never treats
「․․」 as a traversal segment.  After cwd resolution the path becomes
/tmp/safe/[U+2024][U+2024]/etc/passwd which legitimately matches the
declared "/tmp/safe/*" scope via fnmatch (whose * matches across /),
so the proxy's PERMIT decision is correct.

Fix:
- Remove the U+2024 dot-confusable path from the pass condition; keep it
  as telemetry/diagnostic output only
- Gate pass/fail solely on the null-byte injection check, which the proxy
  handles correctly (always DENY)
- Update test docstring and title to accurately describe what is checked
- Update README.md and site/content/source/README.md Phase-2 table row
  to reflect the narrowed scope of the input-sanitization check

The 22/22 count is unchanged — the test passes correctly after the fix.
Correcting the expectation restores reproducible 22/22 conformance.

Closes #38 (test re-scoped; no proxy code change required).
The site/content/source/ mirror must be regenerated via sync_source_docs.py
rather than edited by hand. The previous commit wrote the correct content
body but left the source_sha256 frontmatter stale.  Running the sync
script updates the SHA256 to match the new README.md.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant