Skip to content

fix(assail): char-boundary-aware advance in Isabelle cartouche skip (regression from #49)#65

Merged
hyperpolymath merged 1 commit into
mainfrom
fix/isabelle-cartouche-utf8-boundary
May 27, 2026
Merged

fix(assail): char-boundary-aware advance in Isabelle cartouche skip (regression from #49)#65
hyperpolymath merged 1 commit into
mainfrom
fix/isabelle-cartouche-utf8-boundary

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

skip_cartouche_end advanced its byte index by 1 in the no-open / no-close branch, which puts j inside a multi-byte UTF-8 sequence when the cartouche body contains non-ASCII (¬, , , 🎉, etc.). The next iteration's haystack[j..].starts_with(open) then panics:

thread 'main' panicked at src/assail/analyzer.rs:5648:20:
start byte index 89 is not a char boundary; it is inside '¬' (bytes 88..90)

Discovery

./target/release/panic-attack assail /home/hyperpolymath/developer/repos/echidna from the 2026-05-26 estate reconnaissance crashed on a real .thy file inside echidna:

text \<open>
  Double negation elimination: ¬¬A is equivalent to A.
  ...
\<close>

Subsetting echidna to src/ worked around it; this is the proper fix.

Fix

In the no-open / no-close branch, advance by len_utf8() of the current char rather than 1 byte. chars().next() is guaranteed non-empty there because j < haystack.len().

Tests

Two new regression tests in assail::analyzer::tests:

  • isabelle_cartouche_with_non_ascii_does_not_panic — sampled body from the actual crash (¬¬A, ∀x, ).
  • isabelle_cartouche_emoji_grapheme_clusters — 4-byte UTF-8 (🎉) exercises the full multi-byte range, including the path that 2/3-byte chars wouldn't catch.

Test plan

  • cargo test --lib assail::analyzer::tests::isabelle10/10 pass (8 existing + 2 new).
  • cargo build --release clean.
  • Reproducer: ./target/release/panic-attack assail /home/hyperpolymath/developer/repos/echidna now completes cleanly with 44 weak points (was: panic).
  • CI on this PR.

Regression from #49 (Isabelle prose-stripper added in 2026-05-26).

🤖 Generated with Claude Code

…regression from #49)

`skip_cartouche_end` advanced its byte index by 1 in the no-open/no-close
branch, which puts `j` inside a multi-byte UTF-8 sequence when the
cartouche body contains non-ASCII (`¬`, `∀`, `⟹`, `🎉`, etc.). The next
iteration's `haystack[j..].starts_with(open)` then panics with

  thread 'main' panicked at src/assail/analyzer.rs:5648:20:
  start byte index 89 is not a char boundary; it is inside '¬' (...)

discovered on `echidna` full-tree scans during the 2026-05-26 estate
reconnaissance. Subsetting to `src/` worked around it; the proper fix
is to advance by `len_utf8()` of the current char.

Two regression tests: one with a sampled echidna text-cartouche body
(`¬¬A`, `∀x`, `⟹`), one with a 4-byte UTF-8 emoji to exercise the
full multi-byte range. Reproducer (full-tree assail on echidna) now
completes cleanly with 44 weak points.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@hyperpolymath hyperpolymath enabled auto-merge (squash) May 26, 2026 14:09
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 45 issues detected

Severity Count
🔴 Critical 4
🟠 High 16
🟡 Medium 25

⚠️ Action Required: Critical security issues found!

View findings
[
  {
    "reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
    "type": "unpinned_action",
    "file": "governance.yml",
    "action": "pin_sha",
    "rule_module": "workflow_audit",
    "severity": "high"
  },
  {
    "reason": "Nickel file missing SPDX-License-Identifier header (1 occurrences, CWE-1104)",
    "type": "ncl_missing_spdx",
    "file": "/home/runner/work/panic-attack/panic-attack/reports/panic-attack-20260211180017.ncl",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "expect() in hot path (2 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/panic-attack/panic-attack/src/attestation/chain.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "unwrap_or(0) with dangerous default (1 occurrences, CWE-754)",
    "type": "unwrap_dangerous_default",
    "file": "/home/runner/work/panic-attack/panic-attack/src/attestation/evidence.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "critical"
  },
  {
    "reason": "unwrap_or(0) with dangerous default (1 occurrences, CWE-754)",
    "type": "unwrap_dangerous_default",
    "file": "/home/runner/work/panic-attack/panic-attack/src/ambush/mod.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "critical"
  },
  {
    "reason": "unwrap_or(0) with dangerous default (3 occurrences, CWE-754)",
    "type": "unwrap_dangerous_default",
    "file": "/home/runner/work/panic-attack/panic-attack/src/kanren/strategy.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "critical"
  },
  {
    "reason": "unwrap_or(0) with dangerous default (3 occurrences, CWE-754)",
    "type": "unwrap_dangerous_default",
    "file": "/home/runner/work/panic-attack/panic-attack/src/axial/mod.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "critical"
  },
  {
    "reason": "expect() in hot path (4 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/panic-attack/panic-attack/src/assail/analyzer.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  },
  {
    "reason": "unwrap() without prior check -- DoS via panic (4 occurrences, CWE-754)",
    "type": "unwrap_without_check",
    "file": "/home/runner/work/panic-attack/panic-attack/benches/scan_bench.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "high"
  },
  {
    "reason": "expect() in hot path (2 occurrences, CWE-754)",
    "type": "expect_in_hot_path",
    "file": "/home/runner/work/panic-attack/panic-attack/benches/scan_bench.rs",
    "action": "flag",
    "rule_module": "code_safety",
    "severity": "medium"
  }
]

Powered by Hypatia Neurosymbolic CI/CD Intelligence

@hyperpolymath hyperpolymath merged commit 8ced37b into main May 27, 2026
26 checks passed
@hyperpolymath hyperpolymath deleted the fix/isabelle-cartouche-utf8-boundary branch May 27, 2026 04:42
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