From e7c5e66d7492854192fd6fff2f7c28f2187e28aa Mon Sep 17 00:00:00 2001 From: Adam Moussa Date: Thu, 25 Jun 2026 13:49:51 -0400 Subject: [PATCH] Mirror box-side title validation exactly in the workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Address security-review F1/F3: the workflow re-check used a POSIX [[:cntrl:]] grep (missed the C1 range the box-side sanitizer strips) and wc -m (byte count, not chars). Replace both with a single python3 check whose accept condition is byte-for-byte identical to sanitize_pr_title — rejects [\x00-\x1f\x7f-\x9f] and caps at 70 characters — so the defense-in-depth re-validation genuinely matches the box path. --- .github/workflows/agent-team-apply-verify.yml | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/.github/workflows/agent-team-apply-verify.yml b/.github/workflows/agent-team-apply-verify.yml index 62995ba..c1b25dc 100644 --- a/.github/workflows/agent-team-apply-verify.yml +++ b/.github/workflows/agent-team-apply-verify.yml @@ -1286,16 +1286,17 @@ jobs: # smuggle newlines/control chars/over-long content into the PR metadata. title="$fallback_title" if [ -n "$PR_TITLE" ]; then - # Reject any control char (incl. newline/tab/NUL/DEL) or > 70 chars. - # POSIX [[:cntrl:]] under LC_ALL=C (no GNU-only `grep -P`): matches - # 0x00-0x1f + 0x7f. C1 (0x80-0x9f) is already stripped box-side by - # sanitize_pr_title; this is the defense-in-depth re-check (§4.6). - if printf '%s' "$PR_TITLE" | LC_ALL=C grep -q '[[:cntrl:]]'; then - echo "::warning::pr_title rejected (control chars); using fallback" - elif [ "$(printf '%s' "$PR_TITLE" | wc -m)" -gt 70 ]; then - echo "::warning::pr_title rejected (too long); using fallback" - else + # Re-validate the box-supplied title as defense-in-depth (§4.6), + # BYTE-FOR-BYTE identical to agent_team.dispatcher.sanitize_pr_title's + # acceptance test: reject any C0/C1 control char or DEL + # ([\x00-\x1f\x7f-\x9f] — note this DOES cover C1, which a POSIX + # [[:cntrl:]] grep misses) and cap at 70 *characters* (not bytes, so a + # multibyte title is not spuriously rejected). python3 is present on + # the runner; an undecodable/invalid title exits non-zero -> fallback. + if printf '%s' "$PR_TITLE" | python3 -c 'import sys, re; t = sys.stdin.read(); sys.exit(0 if t and not re.search(r"[\x00-\x1f\x7f-\x9f]", t) and len(t) <= 70 else 1)'; then title="$PR_TITLE" + else + echo "::warning::pr_title rejected (control chars or >70 chars); using fallback" fi fi # The provenance (task id, diff hash, head) lives in the BODY so the