Skip to content

Commit 857beba

Browse files
committed
fix: security scan in purchaser_info, remove disableBlackout
- Add page security scan to request_purchaser_info (parity with npm) - Remove _disable_blackout() method (security risk: exposes card data)
1 parent d82750a commit 857beba

File tree

2 files changed

+32
-18
lines changed

2 files changed

+32
-18
lines changed

pop_pay/injector.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1107,24 +1107,6 @@ async def _enable_blackout(page):
11071107
pass # cross-origin frames may reject — that's OK
11081108
except Exception as e:
11091109
logger.debug("PopBrowserInjector: failed to enable blackout: %s", e)
1110-
1111-
@staticmethod
1112-
async def _disable_blackout(page):
1113-
"""
1114-
Remove the field-level masking CSS from all frames.
1115-
Called after the user clicks submit, or if injection fails.
1116-
"""
1117-
try:
1118-
for frame in page.frames:
1119-
try:
1120-
await frame.evaluate("""() => {
1121-
const style = document.getElementById('pop-pay-blackout');
1122-
if (style) style.remove();
1123-
}""")
1124-
except Exception:
1125-
pass
1126-
except Exception as e:
1127-
logger.debug("PopBrowserInjector: failed to disable blackout: %s", e)
11281110

11291111
@staticmethod
11301112
async def _find_visible_locator(frame, selectors: list):

pop_pay/mcp_server.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)