Skip to content

Harden AI integration per BApp reviewer feedback (v2.1.1) - #6

Merged
liam-portswigger merged 1 commit into
mainfrom
ai-hardening
Jun 19, 2026
Merged

Harden AI integration per BApp reviewer feedback (v2.1.1)#6
liam-portswigger merged 1 commit into
mainfrom
ai-hardening

Conversation

@liam-portswigger

Copy link
Copy Markdown
Owner

Addresses the three items from the BApp Store automated review of the AI integration.

1. AiClient threading (performance correctness)

The single-thread executor meant concurrent scan threads queued on one worker — a thread could hit its 2s timeout while still waiting in the queue, not during the actual call. Replaced with a bounded fixed thread pool (4 daemon workers) so concurrent callers run in parallel and the timeout measures real in-flight time. shutdown() is unchanged.

2. AiTriage prompt injection (security — the serious one)

Attacker-controlled response content was concatenated straight into the prompt, so a crafted server response could instruct the model to return SUPPRESS and silently drop a legitimate finding. Fixed:

  • Trusted fields (finding name/severity) now sit outside the untrusted block; all HTTP-derived content sits inside <http_exchange> tags.
  • System prompt instructs the model to treat tag contents as data only and never obey instructions within them.
  • Delimiter tokens are neutralised in untrusted content so a forged </http_exchange> can't break out.
  • parseVerdict is now strict safe-failure: only a well-formed JSON object whose verdict is exactly SUPPRESS suppresses; anything else (unparseable, wrong type, prose, markdown-fenced) → KEEP. Added tolerant {...} extraction for fenced replies.

3. AiFieldDiscovery prompt injection

Same structural-delimiter treatment — method/path/key-names wrapped in <http_context> tags with a data-only instruction and delimiter neutralisation. The downstream sanitiseAndDedupe allowlist already bounded practical impact; this closes the steering gap.

Diff

9 files, +123 / −47. AI layer only — no scan-check detection logic touched.

Test plan

  • mvn clean package clean.
  • CI green.
  • Reviewer re-check of the three items.

Releases as v2.1.1. Follow-up to submission extension-portal#439.

Three items from the BApp Store automated review:

1. AiClient threading — single-thread executor meant concurrent scan
   threads queued on one worker and could time out while still in the
   queue rather than during the actual call. Replaced with a bounded
   fixed thread pool (4 daemon workers) so concurrent callers are
   serviced in parallel and the 2s timeout measures real in-flight
   time. shutdown() unchanged (works for any ExecutorService).

2. AiTriage prompt injection — attacker-controlled HTTP content (URL,
   headers, up to 400 bytes of body) was concatenated straight into
   the user message, so a crafted response could instruct the model to
   return SUPPRESS and silently drop a real finding. Now:
   - trusted fields (finding name/severity) sit OUTSIDE the untrusted
     block; all HTTP-derived content sits inside <http_exchange> tags;
   - the system prompt instructs the model to treat tag contents as
     data only and never obey instructions within them;
   - delimiter tokens are neutralised in the untrusted content so a
     forged </http_exchange> can't break out of the block;
   - parseVerdict is now strict safe-failure: only a well-formed JSON
     object whose verdict is exactly "SUPPRESS" suppresses; anything
     else (unparseable, wrong type, prose, markdown-fenced) → KEEP.
     Added tolerant {...} extraction for models that fence their JSON.

3. AiFieldDiscovery prompt injection — same structural-delimiter
   treatment: method/path/existing-key-names wrapped in <http_context>
   tags with a treat-as-data-only instruction and delimiter
   neutralisation. (The downstream sanitiseAndDedupe allowlist already
   bounded impact; this closes the steering gap.)

Build verified clean. Version bumped to 2.1.1 across pom, banner, CI,
and docs; CLAUDE.md gotcha #3 updated to note the multi-worker
requirement.
@liam-portswigger
liam-portswigger merged commit 362086d into main Jun 19, 2026
1 check passed
@liam-portswigger
liam-portswigger deleted the ai-hardening branch June 19, 2026 11:14
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