Skip to content

fix(dispatch): replace Lucee-only bare cfabort with abort in public-component 404 branch - #3037

Merged
bpamiri merged 1 commit into
developfrom
peter/issue-3029-cfabort-adobe
Jun 11, 2026
Merged

fix(dispatch): replace Lucee-only bare cfabort with abort in public-component 404 branch#3037
bpamiri merged 1 commit into
developfrom
peter/issue-3029-cfabort-adobe

Conversation

@bpamiri

@bpamiri bpamiri commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator

What

vendor/wheels/Dispatch.cfc's enablePublicComponent=false anti-fingerprinting 404 branch (issue #2233) ended in a bare cfabort;. That statement form is Lucee-only tag-in-script syntax — every Adobe engine compiles it as a reference to an undefined variable and throws Variable CFABORT is undefined at runtime. Because the stock app's homepage is served by the public component, GET / on a stock Adobe install in testing/production hit this branch on every request and returned HTTP 500 (composite Not Found + error template) instead of a clean 404. Root cause of discussion #3023.

Changes

  • One-token fix: cfabort; → script keyword abort; (Dispatch.cfc:404), with a comment explaining why the bare form is forbidden.
  • Structural guard spec vendor/wheels/tests/specs/security/BareCfabortGuardSpec.cfc: scans vendor/wheels/**/*.cfc for bare script-context cfabort statements with line-anchored matching (comment-only lines skipped per Anti-Pattern 14 spirit — no whole-file non-greedy comment-strip regex, which hangs Lucee 7; tag-context <cfabort> in .cfm/tag-based CFCs stays legal). The branch has zero execution coverage on any engine (an executed abort would kill the test runner), so the structural scan is the regression gate. The forbidden token is built by concatenation so the spec can never flag itself.
  • PublicComponentProductionSpec.cfc: documents that the branch now ends in abort; and why; widens the source-inspection window (400→800 chars) past the new explanatory comments.
  • CLAUDE.md: new Cross-Engine Invariant 13 — bare tag-in-script statements without parentheses are Lucee-only; use script keywords or the parenthesized call form.
  • changelog.d fragment (fixed).

Test evidence

TDD red→green (guard spec, Lucee 7 + SQLite docker harness):

  • RED before fix: 417Found bare tag-in-script 'cfabort' statement(s) at: /Dispatch.cfc:400
  • GREEN after fix: 200 — 1 pass / 0 fail / 0 error

Live verification, environment=testing (acceptance gate):

Engine State GET /wheels/info GET /
Adobe 2023 before fix (RED) HTTP 500, 20,799 bytes, Not Found + error template containing Variable CFABORT is undefined (×2) HTTP 500, same composite error body
Adobe 2023 after fix (GREEN) HTTP 404, body Not Found (9 bytes, no error template) HTTP 404, body Not Found (9 bytes)
Lucee 7 after fix (control) HTTP 404, body Not Found (10 bytes) HTTP 404, body Not Found (10 bytes)

Suites:

  • Lucee 7 + SQLite full core suite: baseline (pre-change) 4374 pass / 12 fail / 0 error → after change 4375 pass / 12 fail / 0 error (+1 = new guard spec; the 12 failures are the known pre-existing internal.testClientSpec container artifacts on both runs).
  • Adobe 2023 + SQLite, both touched security bundles (BareCfabortGuardSpec + PublicComponentProductionSpec): 46 pass / 0 fail / 0 error.

Fixes #3029

🤖 Generated with Claude Code

…omponent 404 branch

The enablePublicComponent=false anti-fingerprinting block in Dispatch.cfc
ended with a bare 'cfabort;' statement. That tag-in-script form is
Lucee-only: every Adobe engine compiles it as a reference to an undefined
variable and throws 'Variable CFABORT is undefined' at runtime. Since the
stock app homepage is served by the public component, GET / on a stock
Adobe install in testing/production returned HTTP 500 (composite
'Not Found' + error template) on every request instead of a clean 404.

- One-token fix: 'cfabort;' -> script keyword 'abort;'.
- New structural guard spec (BareCfabortGuardSpec) scans
  vendor/wheels/**/*.cfc for bare script-context cfabort statements with
  line-anchored matching (comment-only lines skipped; tag-context
  cfabort in .cfm/tag-based CFCs stays legal) and fails on any hit. The
  branch has no execution coverage on any engine (an executed abort
  would kill the test runner), so the structural scan is the gate.
- PublicComponentProductionSpec: note the branch now ends in 'abort;'
  and widen the source-inspection window past the new comments.
- CLAUDE.md: new Cross-Engine Invariant 13 documenting the bare
  tag-in-script statement trap.

Fixes #3029

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: Peter Amiri <peter@alurium.com>

@wheels-bot wheels-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wheels Bot — Reviewer

TL;DR: This PR replaces the Lucee-only bare cfabort; statement in Dispatch.cfc's enablePublicComponent=false anti-fingerprinting branch with the cross-engine script keyword abort;, and adds a structural guard spec so the bare form can never reappear under vendor/wheels/**/*.cfc. The one-token fix is correct, the live Adobe 2023 before/after evidence (500 → 404) is credible, the TDD red→green sequence for the guard spec is documented, and the commit, changelog fragment, and CLAUDE.md invariant are all in order. Verdict: comment — the diff is sound; the only findings are one docs gap and one non-blocking robustness note on the guard spec.

Correctness

No findings. Verification performed against head c5caa5730:

  • vendor/wheels/Dispatch.cfc:404 now reads abort;, which is valid CFScript on Lucee 5/6/7, Adobe CF 2018–2025, and BoxLang. The surrounding 404 contract (cfheader(statuscode=404)cfcontentwriteOutput("Not Found")abort;) is intact and still satisfies the issue #2233 anti-fingerprinting requirement.
  • I grepped every remaining cfabort occurrence under vendor/wheels and checked each against the guard's skip rules: Dispatch.cfc:395,398 and controller/rendering.cfc:86 are comment-only lines (skipped by the trimmed-prefix check), public/views/cli.cfm:1085 and wheelstest/system/util/XMLConverter.cfc:255 are tag-form <cfabort> (no trailing semicolon, preceded by an angle bracket — never matches (^|[\s;{}])cfabort\s*;), and PublicComponentProductionSpec.cfc:211 has the token followed by a word, not a semicolon. The guard passes today for the right reasons, not by accident.
  • The widened 800-char inspection window in PublicComponentProductionSpec.cfc:206 is sufficient: the distance from the !application.wheels.enablePublicComponent gate to statuscode=404 is roughly 530 characters including the new explanatory comments, leaving ~270 chars of headroom.
  • I also swept vendor/wheels for sibling bare tag-in-script statements (cfflush;, cfexit;, cfrethrow;, etc.) — none exist, so the guard's cfabort-only scope leaves no latent instance of the same bug class uncovered today.

Cross-engine

No findings. The new spec itself was checked against the documented invariants: Left() is only called with constant lengths 1–2 (invariant 8 concerns length 0), the closures declare all state with var inside the it() body (no outer-local capture), # characters in string literals are escaped as ##3029, and no inline-closure-as-constructor-arg shape appears. The PR's own test evidence covers Lucee 7 (full suite, +1 pass) and Adobe 2023 (both touched security bundles green), which matches the CLAUDE.md cross-engine verification bar for an Adobe-targeted fix.

Tests

Non-blocking robustness note on vendor/wheels/tests/specs/security/BareCfabortGuardSpec.cfc:72-75: the comment-skip only handles comment-only lines —

if (Left(trimmed, 2) == "//" || Left(trimmed, 1) == "*" || Left(trimmed, 2) == "/*") {
    continue;
}
if (REFindNoCase(pattern, trimmed)) {

A future code line with a trailing comment containing the literal token plus semicolon (e.g. abort; // was cfabort;) would false-positive, because the regex runs over the full trimmed line. No such line exists today (verified by grep), and the failure mode is a loud, self-describing test failure rather than a shipped bug, so this does not block. If you want to harden it cheaply: strip a trailing //-to-end-of-line segment from trimmed before the REFindNoCase, keeping the existing whole-line skips. Equally fine to leave as-is.

Otherwise the test work is solid: BDD spec extending wheels.WheelsTest (not RocketUnit), documented red→green (417 with offender path → 200), self-exclusion plus token-by-concatenation so the spec can't flag itself, and a sensible rationale for why structural scanning replaces execution coverage (an executed abort would kill the runner).

Docs

.ai/wheels/cross-engine-compatibility.md was not updated. Every recent sibling of the new CLAUDE.md invariant has a parallel deep-reference section in that file — invariant 10 (attributeCollection, line 303), invariant 11 (local in catch, line 252), invariant 12 (for in finally, line 173) — and CLAUDE.md's Cross-Engine Invariants section explicitly points there as the deep reference. Please add a short "Bare tag-in-script statements (Adobe CF)" section mirroring the new invariant 13: the WRONG/RIGHT snippet (cfabort; vs abort;), the Adobe Variable CFABORT is undefined failure mode, and a pointer to BareCfabortGuardSpec.cfc and issue #3029. This is the only change I'm asking for.

Everything else checks out: changelog fragment changelog.d/3029-dispatch-bare-cfabort-adobe.fixed.md follows the <slug>.<type>.md convention with a complete bullet (no direct CHANGELOG.md edit), and the CLAUDE.md invariant entry is accurate and appropriately scoped.

Commits

No findings. Single commit c5caa5730: valid type/scope (fix(dispatch)), header 89 chars (≤ 100), body lines within limits, explains the "why" (Adobe variable-reference compilation of the bare token), references the issue, and carries both the DCO Signed-off-by trailer and co-author credit.

@bpamiri
bpamiri merged commit beca3f8 into develop Jun 11, 2026
6 checks passed
@bpamiri
bpamiri deleted the peter/issue-3029-cfabort-adobe branch June 11, 2026 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

dispatch: bare cfabort crashes every Adobe engine in the public-component 404 branch

1 participant