Remove breach simulator product surface
Browse files- __pycache__/server.cpython-310.pyc +2 -2
- dashboard.html +3 -30
- dashboard.js +0 -20
- index.html +4 -12
- server.py +0 -84
__pycache__/server.cpython-310.pyc
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:4dfdbd3981bd3b76cbdbc25c46a5df6cf5bcb4def45fce66b992d59e2208b36c
|
| 3 |
+
size 138148
|
dashboard.html
CHANGED
|
@@ -12,10 +12,9 @@
|
|
| 12 |
|
| 13 |
<body>
|
| 14 |
<!-- GLOBAL APP SWITCHER -->
|
| 15 |
-
<div class="global-switcher">
|
| 16 |
-
<a href="index.html" class="active global-link"><i data-lucide="shield-check"></i> REDACT-AI</a>
|
| 17 |
-
|
| 18 |
-
</div>
|
| 19 |
<!-- SIDEBAR -->
|
| 20 |
<aside class="sidebar" id="sidebar">
|
| 21 |
<div class="sidebar__header">
|
|
@@ -52,9 +51,6 @@
|
|
| 52 |
<button class="sidebar__link" data-page="ai-leak" id="nav-ai-leak" onclick="switchPage('ai-leak')">
|
| 53 |
<span class="sidebar__icon"><i data-lucide="scan-search"></i></span> <span class="sidebar__link-text">AI Leak Scan</span>
|
| 54 |
</button>
|
| 55 |
-
<button class="sidebar__link" data-page="breach-simulator" id="nav-breach-simulator" onclick="switchPage('breach-simulator')">
|
| 56 |
-
<span class="sidebar__icon"><i data-lucide="zap"></i></span> <span class="sidebar__link-text">Breach Sim</span>
|
| 57 |
-
</button>
|
| 58 |
<button class="sidebar__link" data-page="synthetic-attack" id="nav-synthetic-attack" onclick="switchPage('synthetic-attack')">
|
| 59 |
<span class="sidebar__icon"><i data-lucide="syringe"></i></span> <span class="sidebar__link-text">Synthetic Tests</span>
|
| 60 |
</button>
|
|
@@ -593,29 +589,6 @@
|
|
| 593 |
</div>
|
| 594 |
</div>
|
| 595 |
|
| 596 |
-
<!-- ===== PAGE: BREACH SIMULATOR ===== -->
|
| 597 |
-
<div class="page" id="page-breach-simulator">
|
| 598 |
-
<div class="tool-hero">
|
| 599 |
-
<div>
|
| 600 |
-
<div class="flow-kicker"><i data-lucide="zap"></i> Breach Simulator</div>
|
| 601 |
-
<h2>Run safe breach drills without attacking your systems.</h2>
|
| 602 |
-
<p>Generate a tabletop attack path, expected detections, evidence checklist, and response scorecard for privacy and AI incidents.</p>
|
| 603 |
-
</div>
|
| 604 |
-
</div>
|
| 605 |
-
<div class="tool-card">
|
| 606 |
-
<div class="tool-form tool-form--three">
|
| 607 |
-
<select class="form-input" id="breach-scenario">
|
| 608 |
-
<option value="pii_exfiltration">PII exfiltration</option>
|
| 609 |
-
<option value="ai_prompt_leak">AI prompt leak</option>
|
| 610 |
-
<option value="tracker_consent_bypass">Consent bypass</option>
|
| 611 |
-
</select>
|
| 612 |
-
<input type="text" class="form-input" id="breach-asset" value="web_app" placeholder="Asset, e.g. web_app">
|
| 613 |
-
<button class="btn btn--primary" id="breach-btn"><i data-lucide="play"></i> Build Drill</button>
|
| 614 |
-
</div>
|
| 615 |
-
</div>
|
| 616 |
-
<div class="tool-output" id="breach-output"></div>
|
| 617 |
-
</div>
|
| 618 |
-
|
| 619 |
<!-- ===== PAGE: SYNTHETIC ATTACK SUITE ===== -->
|
| 620 |
<div class="page" id="page-synthetic-attack">
|
| 621 |
<div class="tool-hero">
|
|
|
|
| 12 |
|
| 13 |
<body>
|
| 14 |
<!-- GLOBAL APP SWITCHER -->
|
| 15 |
+
<div class="global-switcher">
|
| 16 |
+
<a href="index.html" class="active global-link"><i data-lucide="shield-check"></i> REDACT-AI</a>
|
| 17 |
+
</div>
|
|
|
|
| 18 |
<!-- SIDEBAR -->
|
| 19 |
<aside class="sidebar" id="sidebar">
|
| 20 |
<div class="sidebar__header">
|
|
|
|
| 51 |
<button class="sidebar__link" data-page="ai-leak" id="nav-ai-leak" onclick="switchPage('ai-leak')">
|
| 52 |
<span class="sidebar__icon"><i data-lucide="scan-search"></i></span> <span class="sidebar__link-text">AI Leak Scan</span>
|
| 53 |
</button>
|
|
|
|
|
|
|
|
|
|
| 54 |
<button class="sidebar__link" data-page="synthetic-attack" id="nav-synthetic-attack" onclick="switchPage('synthetic-attack')">
|
| 55 |
<span class="sidebar__icon"><i data-lucide="syringe"></i></span> <span class="sidebar__link-text">Synthetic Tests</span>
|
| 56 |
</button>
|
|
|
|
| 589 |
</div>
|
| 590 |
</div>
|
| 591 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 592 |
<!-- ===== PAGE: SYNTHETIC ATTACK SUITE ===== -->
|
| 593 |
<div class="page" id="page-synthetic-attack">
|
| 594 |
<div class="tool-hero">
|
dashboard.js
CHANGED
|
@@ -1642,26 +1642,6 @@ function initProductTools() {
|
|
| 1642 |
finally { btn.disabled = false; btn.innerHTML = '<i data-lucide="search-check"></i> Run Quick Check'; if (typeof lucide !== 'undefined') lucide.createIcons(); }
|
| 1643 |
});
|
| 1644 |
|
| 1645 |
-
document.getElementById('breach-btn')?.addEventListener('click', async () => {
|
| 1646 |
-
const btn = document.getElementById('breach-btn');
|
| 1647 |
-
const out = document.getElementById('breach-output');
|
| 1648 |
-
btn.disabled = true; btn.innerHTML = '<i data-lucide="loader-2" class="spin"></i> Building...';
|
| 1649 |
-
try {
|
| 1650 |
-
const res = await fetch(API_BASE + '/breach/simulate', {
|
| 1651 |
-
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
| 1652 |
-
body: JSON.stringify({ scenario: document.getElementById('breach-scenario')?.value, asset: document.getElementById('breach-asset')?.value || 'web_app' })
|
| 1653 |
-
});
|
| 1654 |
-
const data = await res.json();
|
| 1655 |
-
if (!res.ok) throw new Error(data.detail || 'Simulation failed');
|
| 1656 |
-
render(out, `
|
| 1657 |
-
<div class="tool-score"><strong>${escapeFlowHtml(data.scenario)}</strong><span>${escapeFlowHtml(data.safety)}</span></div>
|
| 1658 |
-
<div class="tool-timeline">${data.stages.map(s => `<div><b>${s.step}. ${escapeFlowHtml(s.phase)}</b><span>${escapeFlowHtml(s.what_happens)}</span></div>`).join('')}</div>
|
| 1659 |
-
<div class="tool-grid">${data.controls_to_verify.map(c => `<div class="tool-result-item"><strong>Control</strong><span>${escapeFlowHtml(c)}</span></div>`).join('')}</div>
|
| 1660 |
-
`);
|
| 1661 |
-
} catch (err) { render(out, `<div class="tool-result-item"><strong>Simulation failed</strong><span>${escapeFlowHtml(err.message)}</span></div>`); }
|
| 1662 |
-
finally { btn.disabled = false; btn.innerHTML = '<i data-lucide="play"></i> Build Drill'; if (typeof lucide !== 'undefined') lucide.createIcons(); }
|
| 1663 |
-
});
|
| 1664 |
-
|
| 1665 |
document.getElementById('synthetic-btn')?.addEventListener('click', async () => {
|
| 1666 |
const btn = document.getElementById('synthetic-btn');
|
| 1667 |
const out = document.getElementById('synthetic-output');
|
|
|
|
| 1642 |
finally { btn.disabled = false; btn.innerHTML = '<i data-lucide="search-check"></i> Run Quick Check'; if (typeof lucide !== 'undefined') lucide.createIcons(); }
|
| 1643 |
});
|
| 1644 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1645 |
document.getElementById('synthetic-btn')?.addEventListener('click', async () => {
|
| 1646 |
const btn = document.getElementById('synthetic-btn');
|
| 1647 |
const out = document.getElementById('synthetic-output');
|
index.html
CHANGED
|
@@ -18,10 +18,9 @@
|
|
| 18 |
<!-- NAVBAR -->
|
| 19 |
<nav class="navbar" id="navbar">
|
| 20 |
<!-- GLOBAL APP SWITCHER (Top Tier of Header) -->
|
| 21 |
-
<div class="global-switcher">
|
| 22 |
-
<a href="index.html" class="active global-link"><i data-lucide="shield-check"></i> REDACT-AI</a>
|
| 23 |
-
|
| 24 |
-
</div>
|
| 25 |
<div class="container">
|
| 26 |
<a href="#" class="navbar__logo">
|
| 27 |
<svg class="logo-svg" viewBox="0 0 48 48" width="36" height="36" xmlns="http://www.w3.org/2000/svg" style="margin-right:8px;">
|
|
@@ -66,14 +65,7 @@
|
|
| 66 |
<span class="dropdown-desc">Discover leaked sensitive models</span>
|
| 67 |
</div>
|
| 68 |
</a>
|
| 69 |
-
<a href="dashboard.html#
|
| 70 |
-
<div class="dropdown-icon"><i data-lucide="zap"></i></div>
|
| 71 |
-
<div class="dropdown-text">
|
| 72 |
-
<span class="dropdown-name">Breach Simulator</span>
|
| 73 |
-
<span class="dropdown-desc">Simulate data breach scenarios</span>
|
| 74 |
-
</div>
|
| 75 |
-
</a>
|
| 76 |
-
<a href="dashboard.html#prompt-scanner" class="dropdown-link">
|
| 77 |
<div class="dropdown-icon"><i data-lucide="terminal-square"></i></div>
|
| 78 |
<div class="dropdown-text">
|
| 79 |
<span class="dropdown-name">Prompt Risk Scanner</span>
|
|
|
|
| 18 |
<!-- NAVBAR -->
|
| 19 |
<nav class="navbar" id="navbar">
|
| 20 |
<!-- GLOBAL APP SWITCHER (Top Tier of Header) -->
|
| 21 |
+
<div class="global-switcher">
|
| 22 |
+
<a href="index.html" class="active global-link"><i data-lucide="shield-check"></i> REDACT-AI</a>
|
| 23 |
+
</div>
|
|
|
|
| 24 |
<div class="container">
|
| 25 |
<a href="#" class="navbar__logo">
|
| 26 |
<svg class="logo-svg" viewBox="0 0 48 48" width="36" height="36" xmlns="http://www.w3.org/2000/svg" style="margin-right:8px;">
|
|
|
|
| 65 |
<span class="dropdown-desc">Discover leaked sensitive models</span>
|
| 66 |
</div>
|
| 67 |
</a>
|
| 68 |
+
<a href="dashboard.html#prompt-scanner" class="dropdown-link">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 69 |
<div class="dropdown-icon"><i data-lucide="terminal-square"></i></div>
|
| 70 |
<div class="dropdown-text">
|
| 71 |
<span class="dropdown-name">Prompt Risk Scanner</span>
|
server.py
CHANGED
|
@@ -2642,12 +2642,6 @@ class PromptRiskScanRequest(BaseModel):
|
|
| 2642 |
context: str = "general"
|
| 2643 |
|
| 2644 |
|
| 2645 |
-
class BreachSimulationRequest(BaseModel):
|
| 2646 |
-
scenario: str = "pii_exfiltration"
|
| 2647 |
-
asset: str = "web_app"
|
| 2648 |
-
maturity: str = "standard"
|
| 2649 |
-
|
| 2650 |
-
|
| 2651 |
class SyntheticAttackSuiteRequest(BaseModel):
|
| 2652 |
industry: str = "saas"
|
| 2653 |
volume: int = 12
|
|
@@ -3442,79 +3436,6 @@ def _prompt_risk_report(prompt: str, context: str = "general") -> dict:
|
|
| 3442 |
}
|
| 3443 |
|
| 3444 |
|
| 3445 |
-
def _breach_simulation(req: BreachSimulationRequest) -> dict:
|
| 3446 |
-
scenario = (req.scenario or "pii_exfiltration").lower()
|
| 3447 |
-
catalog = {
|
| 3448 |
-
"pii_exfiltration": {
|
| 3449 |
-
"name": "PII Exfiltration Tabletop",
|
| 3450 |
-
"goal": "Validate whether sensitive records can leave the product without detection.",
|
| 3451 |
-
"stages": [
|
| 3452 |
-
("Initial access", "Compromised support account attempts unusual export."),
|
| 3453 |
-
("Discovery", "Actor searches for customer, invoice, and document exports."),
|
| 3454 |
-
("Collection", "Actor creates high-volume report containing PII."),
|
| 3455 |
-
("Exfiltration", "Actor attempts download or webhook delivery."),
|
| 3456 |
-
("Response", "Team validates alert, containment, and customer notification path."),
|
| 3457 |
-
],
|
| 3458 |
-
"mitre": ["TA0001", "TA0007", "TA0009", "TA0010"],
|
| 3459 |
-
},
|
| 3460 |
-
"ai_prompt_leak": {
|
| 3461 |
-
"name": "AI Prompt Leakage Tabletop",
|
| 3462 |
-
"goal": "Test if prompts, secrets, or customer data can be extracted from AI workflows.",
|
| 3463 |
-
"stages": [
|
| 3464 |
-
("Injection", "User tries to override assistant policy."),
|
| 3465 |
-
("Tool abuse", "Prompt requests hidden tool output or customer records."),
|
| 3466 |
-
("Sensitive output", "Model attempts to echo confidential context."),
|
| 3467 |
-
("Guardrail response", "App blocks, redacts, or escalates the event."),
|
| 3468 |
-
],
|
| 3469 |
-
"mitre": ["LLM01", "LLM06", "LLM07", "LLM08"],
|
| 3470 |
-
},
|
| 3471 |
-
"tracker_consent_bypass": {
|
| 3472 |
-
"name": "Consent Bypass Drill",
|
| 3473 |
-
"goal": "Check whether trackers fire before consent or after consent withdrawal.",
|
| 3474 |
-
"stages": [
|
| 3475 |
-
("Fresh visit", "Open site with no prior cookies."),
|
| 3476 |
-
("Pre-consent observation", "Monitor third-party requests and cookies."),
|
| 3477 |
-
("Withdraw consent", "Reject or withdraw tracking categories."),
|
| 3478 |
-
("Regression check", "Confirm trackers stay blocked."),
|
| 3479 |
-
],
|
| 3480 |
-
"mitre": ["Privacy", "Consent", "Vendor Risk"],
|
| 3481 |
-
},
|
| 3482 |
-
}
|
| 3483 |
-
chosen = catalog.get(scenario, catalog["pii_exfiltration"])
|
| 3484 |
-
detections = [
|
| 3485 |
-
"High-volume export from low-privilege or new session",
|
| 3486 |
-
"Sensitive field access outside normal workflow",
|
| 3487 |
-
"New third-party destination or webhook",
|
| 3488 |
-
"Repeated failed access to restricted records",
|
| 3489 |
-
"PII appears in AI prompt, log, analytics event, or browser storage",
|
| 3490 |
-
]
|
| 3491 |
-
controls = [
|
| 3492 |
-
"Role-based export limits and approval for bulk downloads",
|
| 3493 |
-
"PII-aware DLP on logs, prompts, webhooks, and file exports",
|
| 3494 |
-
"Step-up authentication for sensitive actions",
|
| 3495 |
-
"Immutable audit log with actor, purpose, record count, and destination",
|
| 3496 |
-
"Incident runbook covering containment, revocation, notification, and evidence capture",
|
| 3497 |
-
]
|
| 3498 |
-
return {
|
| 3499 |
-
"scenario": chosen["name"],
|
| 3500 |
-
"asset": req.asset,
|
| 3501 |
-
"maturity": req.maturity,
|
| 3502 |
-
"safety": "Tabletop and detection validation only. No destructive payloads are executed.",
|
| 3503 |
-
"goal": chosen["goal"],
|
| 3504 |
-
"stages": [{"step": i + 1, "phase": phase, "what_happens": detail} for i, (phase, detail) in enumerate(chosen["stages"])],
|
| 3505 |
-
"expected_detections": detections,
|
| 3506 |
-
"controls_to_verify": controls,
|
| 3507 |
-
"evidence_to_collect": ["audit logs", "DLP alerts", "SIEM events", "access reviews", "screenshots of blocked action"],
|
| 3508 |
-
"mapping": chosen["mitre"],
|
| 3509 |
-
"scorecard": [
|
| 3510 |
-
{"check": "Alert fired within 5 minutes", "status": "not_run"},
|
| 3511 |
-
{"check": "Owner can identify impacted records", "status": "not_run"},
|
| 3512 |
-
{"check": "Export can be stopped or revoked", "status": "not_run"},
|
| 3513 |
-
{"check": "Customer/regulator notification path is documented", "status": "not_run"},
|
| 3514 |
-
],
|
| 3515 |
-
}
|
| 3516 |
-
|
| 3517 |
-
|
| 3518 |
def _synthetic_attack_suite(req: SyntheticAttackSuiteRequest) -> dict:
|
| 3519 |
volume = max(3, min(int(req.volume or 12), 50))
|
| 3520 |
names = ["Aarav Mehta", "Priya Sharma", "Rahul Gupta", "Ananya Rao", "Neha Kapoor", "Vikram Singh"]
|
|
@@ -4628,11 +4549,6 @@ def prompt_risk_scan(req: PromptRiskScanRequest):
|
|
| 4628 |
return _prompt_risk_report(req.prompt, req.context)
|
| 4629 |
|
| 4630 |
|
| 4631 |
-
@app.post("/api/v1/breach/simulate")
|
| 4632 |
-
def breach_simulate(req: BreachSimulationRequest):
|
| 4633 |
-
return _breach_simulation(req)
|
| 4634 |
-
|
| 4635 |
-
|
| 4636 |
@app.post("/api/v1/synthetic-attack-suite/generate")
|
| 4637 |
def synthetic_attack_suite(req: SyntheticAttackSuiteRequest):
|
| 4638 |
return _synthetic_attack_suite(req)
|
|
|
|
| 2642 |
context: str = "general"
|
| 2643 |
|
| 2644 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2645 |
class SyntheticAttackSuiteRequest(BaseModel):
|
| 2646 |
industry: str = "saas"
|
| 2647 |
volume: int = 12
|
|
|
|
| 3436 |
}
|
| 3437 |
|
| 3438 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 3439 |
def _synthetic_attack_suite(req: SyntheticAttackSuiteRequest) -> dict:
|
| 3440 |
volume = max(3, min(int(req.volume or 12), 50))
|
| 3441 |
names = ["Aarav Mehta", "Priya Sharma", "Rahul Gupta", "Ananya Rao", "Neha Kapoor", "Vikram Singh"]
|
|
|
|
| 4549 |
return _prompt_risk_report(req.prompt, req.context)
|
| 4550 |
|
| 4551 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 4552 |
@app.post("/api/v1/synthetic-attack-suite/generate")
|
| 4553 |
def synthetic_attack_suite(req: SyntheticAttackSuiteRequest):
|
| 4554 |
return _synthetic_attack_suite(req)
|