@@ -500,6 +500,38 @@ async def request_purchaser_info(
500500
501501 This tool does NOT issue a card, does NOT charge anything, and does NOT affect your budget.
502502 """
503+ # -------------------------------------------------------------------
504+ # P1: Automatic security scan (runs whenever page_url is provided)
505+ # -------------------------------------------------------------------
506+ if page_url :
507+ # Check cache first (reuse recent scan within 5 minutes)
508+ cached = snapshot_cache .get (page_url )
509+ if cached and datetime .now () - cached ["timestamp" ] < timedelta (minutes = 5 ):
510+ scan_result = {
511+ "flags" : cached ["flags" ],
512+ "snapshot_id" : cached ["snapshot_id" ],
513+ "safe" : "hidden_instructions_detected" not in cached ["flags" ],
514+ "error" : None ,
515+ }
516+ else :
517+ scan_result = await _scan_page (page_url )
518+
519+ if scan_result .get ("error" ):
520+ # Network/URL error — treat as unsafe; do not inject info
521+ return (
522+ f"Billing info rejected. Security scan failed: { scan_result ['error' ]} "
523+ f"Snapshot ID: { scan_result ['snapshot_id' ]} . "
524+ f"Fix the URL or skip page_url if the page has no associated URL."
525+ )
526+
527+ if not scan_result ["safe" ]:
528+ return (
529+ f"Billing info rejected. Security scan detected hidden prompt injection. "
530+ f"Snapshot ID: { scan_result ['snapshot_id' ]} . "
531+ f"Flags: { scan_result ['flags' ]} . "
532+ f"Do not retry this."
533+ )
534+
503535 if injector is None :
504536 return (
505537 "Billing info injection is not available. "
0 commit comments