opena2a-cli 0.8.11 → 0.8.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -3
- package/dist/commands/guard-harden.js +1 -1
- package/dist/commands/guard-harden.js.map +1 -1
- package/dist/commands/init.js +2 -2
- package/dist/guided/wizard.js +1 -1
- package/dist/index.js +1 -1
- package/dist/natural/llm-fallback.js +1 -1
- package/dist/report/review-html.js +1 -1
- package/dist/scanners/skillguard-checks.d.ts +12 -5
- package/dist/scanners/skillguard-checks.d.ts.map +1 -1
- package/dist/scanners/skillguard-checks.js +27 -20
- package/dist/scanners/skillguard-checks.js.map +1 -1
- package/dist/semantic/command-index.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ npx opena2a-cli review
|
|
|
8
8
|
```
|
|
9
9
|
|
|
10
10
|
```
|
|
11
|
-
OpenA2A Security Review v0.
|
|
11
|
+
OpenA2A Security Review v0.8.11
|
|
12
12
|
|
|
13
13
|
Findings
|
|
14
14
|
-----------------------------------------------
|
|
@@ -44,15 +44,19 @@ opena2a # Interactive guided wizard (no args)
|
|
|
44
44
|
|
|
45
45
|
| Command | What it does |
|
|
46
46
|
|---------|-------------|
|
|
47
|
+
| `opena2a setup` | One-command onboarding — auth, identity, MCP discovery, trust score |
|
|
47
48
|
| `opena2a review` | Full security dashboard — HTML report, 6-phase assessment |
|
|
48
49
|
| `opena2a detect` | Find shadow AI agents, MCP servers, AI configs. Governance score. |
|
|
49
50
|
| `opena2a detect --report` | Executive HTML report |
|
|
50
51
|
| `opena2a detect --export-csv` | Asset inventory for CMDB/ServiceNow |
|
|
51
52
|
| `opena2a init` | Read-only security assessment with trust score |
|
|
52
53
|
| `opena2a protect` | Fix everything — credentials, .gitignore, config signing |
|
|
54
|
+
| `opena2a watch` | Live tail of agent activity events |
|
|
53
55
|
| `opena2a identity create` | Cryptographic identity for your project |
|
|
56
|
+
| `opena2a identity mcp attach` | Auto-discover and attach MCP servers |
|
|
57
|
+
| `opena2a identity integrate` | Wire security tools to identity (audit + trust) |
|
|
54
58
|
| `opena2a harden-soul` | Generate SOUL.md governance rules |
|
|
55
|
-
| `opena2a scan` |
|
|
59
|
+
| `opena2a scan` | 204 security checks via HackMyAgent |
|
|
56
60
|
| `opena2a mcp audit` | Audit MCP server configurations with trust scores |
|
|
57
61
|
| `opena2a guard sign` | Sign config files for tamper detection |
|
|
58
62
|
| `opena2a shield init` | Full security setup — all of the above, one command |
|
|
@@ -65,7 +69,7 @@ Each command routes to a specialized tool, installed on first use:
|
|
|
65
69
|
|---------|------|-------------|
|
|
66
70
|
| `detect` | Shadow AI | Discover AI agents, MCP servers, AI configs |
|
|
67
71
|
| `identity` | [AIM](https://github.com/opena2a-org/agent-identity-management) | Cryptographic identity, audit logs, trust scoring |
|
|
68
|
-
| `scan` | [HackMyAgent](https://github.com/opena2a-org/hackmyagent) |
|
|
72
|
+
| `scan` | [HackMyAgent](https://github.com/opena2a-org/hackmyagent) | 204 security checks, attack simulation, auto-fix |
|
|
69
73
|
| `secrets` | [Secretless AI](https://github.com/opena2a-org/secretless-ai) | Credential management for AI coding tools |
|
|
70
74
|
| `mcp` | MCP Security | Audit, sign, and verify MCP server configurations |
|
|
71
75
|
| `benchmark` | [OASB](https://github.com/opena2a-org/open-agent-security-benchmark) | 222 attack scenarios, compliance scoring |
|
|
@@ -109,7 +109,7 @@ async function guardHarden(targetDir, options) {
|
|
|
109
109
|
}
|
|
110
110
|
return 1;
|
|
111
111
|
}
|
|
112
|
-
// Run extended skill checks (SKILL-
|
|
112
|
+
// Run extended skill checks (SKILL-020 through SKILL-024)
|
|
113
113
|
if (includeSkills) {
|
|
114
114
|
try {
|
|
115
115
|
const extendedFindings = (0, skillguard_checks_js_1.scanSkillDirectory)(resolvedDir);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard-harden.js","sourceRoot":"","sources":["../../src/commands/guard-harden.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"guard-harden.js","sourceRoot":"","sources":["../../src/commands/guard-harden.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/init.js
CHANGED
|
@@ -275,7 +275,7 @@ async function init(options) {
|
|
|
275
275
|
// Shield init hint
|
|
276
276
|
process.stdout.write((0, colors_js_1.dim)(' To set up full Shield protection (11-step orchestration): opena2a shield init') + '\n');
|
|
277
277
|
// Deeper analysis hint
|
|
278
|
-
process.stdout.write((0, colors_js_1.dim)(' For deeper analysis (
|
|
278
|
+
process.stdout.write((0, colors_js_1.dim)(' For deeper analysis (204 checks): opena2a scan --deep') + '\n');
|
|
279
279
|
// Global install hint (only when running via npx)
|
|
280
280
|
if (isRunningViaNpx()) {
|
|
281
281
|
process.stdout.write((0, colors_js_1.dim)(' Tip: Install globally for easier access: npm install -g opena2a-cli') + '\n');
|
|
@@ -799,7 +799,7 @@ function getContextualTip(report) {
|
|
|
799
799
|
}
|
|
800
800
|
if (report.securityScore >= 90) {
|
|
801
801
|
return {
|
|
802
|
-
text: 'Strong baseline. HackMyAgent runs
|
|
802
|
+
text: 'Strong baseline. HackMyAgent runs 204 checks including agent-layer attacks, MCP exploitation, and OASB-1 + OASB-2 compliance scoring.',
|
|
803
803
|
command: 'npx hackmyagent secure',
|
|
804
804
|
};
|
|
805
805
|
}
|
package/dist/guided/wizard.js
CHANGED
|
@@ -7,7 +7,7 @@ const CATEGORIES = [
|
|
|
7
7
|
label: 'Scan & Harden',
|
|
8
8
|
description: 'Find and fix security issues in AI agents',
|
|
9
9
|
commands: [
|
|
10
|
-
{ label: 'Full security scan', command: 'opena2a scan secure', description: '
|
|
10
|
+
{ label: 'Full security scan', command: 'opena2a scan secure', description: '204 security checks with auto-fix' },
|
|
11
11
|
{ label: 'Attack mode', command: 'opena2a scan attack', description: 'Adversarial testing against your agent' },
|
|
12
12
|
{ label: 'Security benchmark', command: 'opena2a benchmark', description: 'OASB benchmark (222 standardized attack scenarios)' },
|
|
13
13
|
{ label: 'Credential scan', command: 'opena2a secrets scan', description: 'Find hardcoded secrets in your codebase' },
|
package/dist/index.js
CHANGED
|
@@ -47,7 +47,7 @@ Quick Start:
|
|
|
47
47
|
$ opena2a init Read-only security assessment (no changes to your project)
|
|
48
48
|
$ opena2a protect Detect and migrate hardcoded credentials
|
|
49
49
|
$ opena2a guard sign Sign config files for tamper detection
|
|
50
|
-
$ opena2a scan secure Run
|
|
50
|
+
$ opena2a scan secure Run 204 security checks on your AI agent
|
|
51
51
|
$ opena2a skill create Scaffold a secure skill (SKILL.md, heartbeat, tests)
|
|
52
52
|
$ opena2a guard harden Scan skills for security issues (--fix to auto-fix)
|
|
53
53
|
$ opena2a harden-skill Harden a skill file (frontmatter, permissions, integrity pin)
|
|
@@ -6,7 +6,7 @@ const colors_js_1 = require("../util/colors.js");
|
|
|
6
6
|
const SYSTEM_PROMPT = `You are OpenA2A CLI, an AI agent security platform. Given a user's natural language query, suggest the most appropriate CLI command.
|
|
7
7
|
|
|
8
8
|
Available commands:
|
|
9
|
-
- opena2a scan secure -- Full security scan (
|
|
9
|
+
- opena2a scan secure -- Full security scan (204 checks)
|
|
10
10
|
- opena2a scan attack -- Attack mode (adversarial testing)
|
|
11
11
|
- opena2a protect -- Detect and migrate credentials to vault
|
|
12
12
|
- opena2a secrets init -- Set up credential protection
|
|
@@ -153,7 +153,7 @@ body{background:var(--bg);color:var(--text);font-family:var(--font);font-size:14
|
|
|
153
153
|
</div>
|
|
154
154
|
<script id="report-data" type="application/json">${jsonData}</script>
|
|
155
155
|
<script>
|
|
156
|
-
(function(){var report=JSON.parse(document.getElementById('report-data').textContent);var pagesRendered={};function esc(s){return s==null?'':String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');}function scoreColor(s){return s>=90?'var(--green)':s>=70?'var(--primary)':s>=50?'var(--medium)':'var(--red)';}document.getElementById('main-nav').addEventListener('click',function(e){var btn=e.target.closest('.nav-tab');if(!btn)return;var pg=btn.getAttribute('data-page');document.querySelectorAll('.nav-tab').forEach(function(t){t.classList.toggle('active',t===btn);});document.querySelectorAll('.page').forEach(function(p){p.classList.toggle('active',p.id==='page-'+pg);});renderPage(pg);});function renderPage(pg){if(pagesRendered[pg])return;pagesRendered[pg]=true;var el=document.getElementById('page-'+pg);switch(pg){case 'overview':el.innerHTML=renderOverview();break;case 'credentials':el.innerHTML=renderCredentials();break;case 'hygiene':el.innerHTML=renderHygiene();break;case 'shield':el.innerHTML=renderShield();break;case 'hma':el.innerHTML=renderHma();break;case 'shadowai':el.innerHTML=renderShadowAi();break;}}window.toggleHmaRows=function(btn){var rows=document.querySelectorAll('.hma-extra-row');var hidden=rows[0]&&rows[0].style.display==='none';for(var i=0;i<rows.length;i++){rows[i].style.display=hidden?'':'none'}btn.textContent=hidden?'Show fewer':'+ Show all checks'};var legacyRiskKb={'SKILL-010':'When a skill reads .env files, it can steal API keys, database passwords, and cloud credentials. Attackers use this to access your accounts, billing, and infrastructure. If the skill is compromised or malicious, every secret in your environment is exposed.','SKILL-005':'Skills that access ~/.ssh, ~/.aws, or credential files can impersonate you across every service you use. A single compromised skill could access your servers, cloud accounts, and private repositories.','SKILL-012':'Accessing cryptocurrency wallets or seed phrases gives an attacker irreversible access to your funds. Unlike passwords, stolen crypto keys cannot be rotated or recovered.','SKILL-002':'Remote fetch-and-execute means the skill downloads code from the internet and runs it. The remote server can change that code at any time, turning a safe skill into a backdoor without any update on your end.','SKILL-004':'Writing files outside the sandbox lets a skill modify system configs, install malware, or overwrite other applications. This breaks the isolation boundary that protects your system.','SKILL-007':'ClickFix social engineering tricks users into copying and pasting malicious commands. The skill appears helpful while guiding users to compromise their own systems.','SKILL-006':'Data exfiltration patterns (base64 encoding + HTTP POST to external servers) are how stolen credentials and source code leave your machine. Even if detection catches the theft later, the data is already gone.','SKILL-011':'Browser data contains saved passwords, session tokens, and cookies. A skill with browser access can hijack your authenticated sessions across every website you use.','SKILL-008':'Reverse shells give an attacker a live terminal on your machine. They can run any command, install persistence, and pivot to other systems on your network.','HEARTBEAT-001':'Heartbeat URLs let skills phone home to external servers. Without verification, an attacker can redirect the heartbeat to a malicious server that sends new instructions to the skill.','HEARTBEAT-004':'Heartbeats requesting dangerous capabilities (shell access, filesystem write) can be remotely activated. The skill stays dormant until the heartbeat server tells it to act.','CONFIG-001':'Session files contain authentication tokens. If exposed, anyone with the file can impersonate your logged-in session without needing your password.','CONFIG-004':'Plaintext API keys in config files are the most common cause of credential breaches. Automated scrapers find them within minutes of a git push.','CONFIG-007':'Unrestricted elevated execution means AI agents can run any command with no approval. A prompt injection or compromised tool can escalate to full system access.','SUPPLY-003':'This skill matches patterns from known malicious campaigns. It may have been installed legitimately but contains code sequences associated with active threats.','SUPPLY-005':'This skill contacts IP addresses used by the ClawHavoc command-and-control infrastructure. This is a strong indicator of compromise.','SUPPLY-006':'References to known malware payload filenames indicate the skill may download or deploy malicious executables.','GIT-002':'Without .env, .pem, and .key in .gitignore, a single careless commit pushes your secrets to git history. Even if deleted later, secrets remain in git history forever.','SKILL-003':'Scheduled tasks run without user awareness. A malicious skill that installs a cron job or heartbeat can persist after the skill itself is removed.','HEARTBEAT-002':'Without hash pinning, a man-in-the-middle can modify heartbeat responses. The skill trusts whatever it receives, even if it has been tampered with.','HEARTBEAT-003':'Unsigned heartbeat files can be replaced by an attacker. A signed heartbeat proves it came from the original publisher and has not been modified.','CONFIG-006':'Auto-following untrusted agents means your system automatically trusts new agents without review. A malicious agent can join and immediately have access.','CONFIG-008':'Disabling the sandbox removes the primary defense against malicious tools. Every tool runs with full system access instead of restricted permissions.','SUPPLY-001':'Unverified publishers cannot be held accountable. Anyone can publish a skill claiming to be from a trusted organization.','SUPPLY-004':'Without an installed hash, you cannot detect if a skill has been modified after installation. A supply chain attacker can silently replace skill code.','SUPPLY-007':'Social engineering instructions that guide users to execute commands are a hallmark of the ClawHavoc campaign targeting AI tool users.','SUPPLY-008':'Password-protected archives bypass antivirus scanning. This is a standard malware distribution technique.','GIT-001':'Without .gitignore, every file in your project can be accidentally committed, including secrets, credentials, and private keys.','SKILL-001':'Unsigned skills cannot prove who created them or that they have not been tampered with. You are trusting code with no chain of custody.','SCAN-001':'Oversized files may be used to evade security scanning. Scanners skip large files, which attackers exploit to hide malicious content.','SUPPLY-002':'Skills not listed in a trusted registry have no community vetting. Anyone can distribute them without accountability.'};window.toggleExpand=function(el){var target=el.nextElementSibling;if(target){target.classList.toggle('open');el.textContent=target.classList.contains('open')?'collapse':'+ show all'}};window.exportCsv=function(tabName){var rows=[];var LF=String.fromCharCode(10);var table=document.querySelector('#page-'+tabName+' table.data-table');if(!table){return}var headers=[];table.querySelectorAll('thead th').forEach(function(th){headers.push(th.textContent.trim())});rows.push(headers.join(','));table.querySelectorAll('tbody tr').forEach(function(tr){var cells=[];tr.querySelectorAll('td').forEach(function(td){var t=td.textContent.trim().replace(/"/g,'""');cells.push('"'+t+'"')});if(cells.length>0)rows.push(cells.join(','))});var csv=rows[0];for(var i=1;i<rows.length;i++){csv+=LF+rows[i]}var blob=new Blob([csv],{type:'text/csv'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='opena2a-review-'+tabName+'.csv';a.click()};window.copyCmd=function(btn){var cmd=btn.getAttribute('data-cmd');if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(cmd).then(function(){btn.textContent='OK';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},1500);});}else{var ta=document.createElement('textarea');ta.value=cmd;ta.style.position='fixed';ta.style.left='-9999px';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);btn.textContent='OK';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},1500);}};window.goToTab=function(tab){var btn=document.querySelector('.nav-tab[data-page="'+tab+'"]');if(btn)btn.click();};function gaugeCircle(score,label){var sz=170,cx=sz/2,cy=sz/2,r=65,sw=10,circ=2*Math.PI*r;var pct=Math.max(0,Math.min(100,score))/100,dash=pct*circ,gap=circ-dash;var clr=score>=90?'#22c55e':score>=70?'#06b6d4':score>=50?'#eab308':'#ef4444';var s='<svg width="'+sz+'" height="'+sz+'" viewBox="0 0 '+sz+' '+sz+'">';s+='<circle cx="'+cx+'" cy="'+cy+'" r="'+r+'" fill="none" stroke="rgba(255,255,255,0.05)" stroke-width="'+sw+'"/>';s+='<circle cx="'+cx+'" cy="'+cy+'" r="'+r+'" fill="none" stroke="'+clr+'" stroke-width="'+sw+'" stroke-dasharray="'+dash+' '+gap+'" stroke-dashoffset="'+(circ*0.25)+'" stroke-linecap="round" transform="rotate(-90 '+cx+' '+cy+')"/>';s+='<text x="'+cx+'" y="'+(cy-6)+'" text-anchor="middle" dominant-baseline="middle" font-size="32" font-weight="700" fill="'+clr+'" font-family="var(--font)">'+score+'</text>';s+='<text x="'+cx+'" y="'+(cy+20)+'" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="600" fill="'+clr+'" font-family="var(--font)">'+esc(label||('out of 100'))+'</text>';s+='</svg>';return s;}function cmdBlock(cmd){return '<div class="cmd-block"><span class="cmd-text">'+esc(cmd)+'</span><button class="copy-btn" data-cmd="'+esc(cmd)+'" onclick="copyCmd(this)">Copy</button></div>';}function statCard(value,label,color){return '<div class="stat-card"><div class="stat-value" style="color:'+color+'">'+esc(String(value))+'</div><div class="stat-label">'+esc(label)+'</div></div>';}function scoreBanner(score,recoverySummary){var clr=scoreColor(score);var h='<div class="score-banner"><div class="score-banner-num" style="color:'+clr+'">'+score+'</div><div class="score-banner-bar"><div class="score-banner-label"><span>Composite Score</span><span>'+score+'/100</span></div><div class="score-banner-track"><div class="score-banner-fill" style="width:'+score+'%;background:'+clr+'"></div></div></div>';if(recoverySummary&&recoverySummary.totalRecoverable>0){var recovBg=score>=70?'rgba(6,182,212,0.15)':score>=50?'rgba(234,179,8,0.15)':'rgba(239,68,68,0.15)';h+='<div class="score-banner-grade" style="color:'+clr+';background:'+recovBg+'">+'+recoverySummary.totalRecoverable+' recoverable</div>';}h+='</div>';return h;}function governanceBanner(score,recoverablePoints){var clr=scoreColor(score);var h='<div class="score-banner"><div class="score-banner-num" style="color:'+clr+'">'+score+'</div><div class="score-banner-bar"><div class="score-banner-label"><span>Governance Score</span><span>'+score+'/100</span></div><div class="score-banner-track"><div class="score-banner-fill" style="width:'+score+'%;background:'+clr+'"></div></div></div>';if(recoverablePoints>0){var projected=Math.min(100,score+recoverablePoints);var recovBg=score>=70?'rgba(6,182,212,0.15)':score>=50?'rgba(234,179,8,0.15)':'rgba(239,68,68,0.15)';h+='<div class="score-banner-grade" style="color:'+clr+';background:'+recovBg+'">path to '+projected+'</div>';}h+='</div>';return h;}var phaseDescriptions={'Project Scan':'Checks .gitignore, lock files, security config, and dependency advisories','Credentials':'Scans source files for hardcoded API keys, tokens, and secrets','Config Integrity':'Verifies cryptographic signatures on monitored config files','Shield Analysis':'Analyzes 7 days of security events, policy violations, and ARP detections','HMA Scan':'Runs HackMyAgent security checks against your AI agent endpoints','Shadow AI':'Detects AI agents, MCP servers, and AI configs; checks governance posture'};function phaseCard(phase){var statusCls='status-'+phase.status;var time=phase.status==='skip'?'--':(phase.durationMs/1000).toFixed(1)+'s';var desc=phaseDescriptions[phase.name]||'';return '<div class="phase-card"><div style="display:flex;justify-content:space-between;align-items:center"><div class="phase-name">'+esc(phase.name)+'</div><span class="status-badge '+statusCls+'">'+esc(phase.status)+'</span></div><div class="phase-detail">'+esc(phase.detail)+'</div>'+(desc?'<div class="phase-desc">'+esc(desc)+'</div>':'')+'<div class="phase-time">'+esc(time)+'</div></div>';}function renderOverview(){var h='';var sevCounts={critical:0,high:0,medium:0,low:0};var findings=report.findings||[];for(var i=0;i<findings.length;i++){var s=findings[i].severity;if(s in sevCounts)sevCounts[s]++;}h+=scoreBanner(report.compositeScore,report.recoverySummary);h+='<div class="stats-grid">';h+=statCard(findings.length,'Findings',findings.length>0?'var(--amber)':'var(--green)');h+=statCard(sevCounts.critical,'Critical',sevCounts.critical>0?'var(--critical)':'var(--text)');h+=statCard(sevCounts.high,'High',sevCounts.high>0?'var(--high)':'var(--text)');h+=statCard(sevCounts.medium,'Medium',sevCounts.medium>0?'var(--medium)':'var(--text)');h+='</div>';h+='<h2 class="section-title">Phase Results</h2><div class="phase-grid">';var phases=report.phases||[];for(var i=0;i<phases.length;i++)h+=phaseCard(phases[i]);h+='</div>';var detectScore=report.detectData?report.detectData.governanceScore:100;var dims=[{name:'Hygiene',weight:30,score:report.initData.trustScore,tab:'hygiene'},{name:'Shield',weight:20,score:report.shieldData.postureScore,tab:'shield'},{name:'Credentials',weight:20,score:phases.length>1?phases[1].score:0,tab:'credentials'},{name:'Integrity',weight:15,score:phases.length>2?phases[2].score:0,tab:'hygiene'},{name:'Shadow AI',weight:15,score:detectScore,tab:'shadowai'}];h+='<div class="score-explainer"><div style="font-size:12px;color:var(--dim);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:12px">Score Breakdown</div><div style="display:flex;flex-direction:column;gap:10px">';for(var i=0;i<dims.length;i++){var d=dims[i];var clr=scoreColor(d.score);h+='<div style="display:grid;grid-template-columns:100px 1fr 60px 50px;align-items:center;gap:10px;cursor:pointer" onclick="goToTab("'+d.tab+'")"><div style="display:flex;align-items:baseline;gap:6px"><span style="font-size:13px;color:var(--muted)">'+esc(d.name)+'</span></div><div style="position:relative;height:8px;background:rgba(255,255,255,0.06);border-radius:4px;overflow:hidden"><div style="position:absolute;left:0;top:0;height:100%;width:'+d.score+'%;background:'+clr+';border-radius:4px;transition:width 0.3s"></div></div><div style="text-align:right;font-size:14px;font-weight:700;color:'+clr+'">'+d.score+'<span style="font-size:11px;color:var(--dim);font-weight:400">/100</span></div><div style="text-align:right;font-size:11px;color:var(--dim)">x '+d.weight+'%</div></div>';}h+='</div><div style="display:flex;justify-content:space-between;align-items:center;border-top:1px solid rgba(51,65,85,0.4);margin-top:12px;padding-top:8px"><div style="display:flex;gap:12px;font-size:12px;color:var(--dim)"><span><strong style="color:var(--green)">A</strong> 90+</span><span><strong style="color:var(--primary)">B</strong> 80+</span><span><strong style="color:var(--medium)">C</strong> 70+</span><span><strong style="color:var(--high)">D</strong> 60+</span><span><strong style="color:var(--red)">F</strong> <60</span></div><div style="font-size:12px;color:var(--dim)">Click a row to view details</div></div></div>';var actions=report.actionItems||[];var actionImpact={'critical':'Immediate risk of credential compromise or data breach','high':'Significant security gap that attackers can exploit','medium':'Moderate risk that weakens your security posture','low':'Minor improvement to harden your defenses','info':'Recommended best practice'};if(actions.length>0){h+='<h2 class="section-title">Action Items</h2><div class="card">';for(var i=0;i<actions.length;i++){var a=actions[i];var impact=actionImpact[a.severity]||'';h+='<div class="action-item"><div class="action-priority">#'+a.priority+'</div><div class="action-content"><div class="action-desc"><span class="sev-badge sev-'+esc(a.severity)+'">'+esc(a.severity)+'</span> '+esc(a.description)+'</div>'+(impact?'<div class="check-desc">'+esc(impact)+'</div>':'')+cmdBlock(a.command)+'<span class="action-link" onclick="goToTab("'+esc(a.tab)+'")">View details</span></div></div>';}h+='</div>';}if(findings.length>0){h+='<h2 class="section-title">Findings</h2><div class="card"><table class="data-table"><thead><tr><th>ID</th><th>Title</th><th>Severity</th><th>Source</th><th>Detail</th></tr></thead><tbody>';var top=findings.slice(0,10);for(var i=0;i<top.length;i++){var f=top[i];h+='<tr><td>'+esc(f.id)+'</td><td>'+esc(f.title)+'</td><td><span class="sev-badge sev-'+esc(f.severity)+'">'+esc(f.severity)+'</span></td><td>'+esc(f.source)+'</td><td style="font-size:11px;color:var(--muted)">'+esc(f.detail)+'</td></tr>';}h+='</tbody></table></div>';}return h;}function renderCredentials(){var data=report.credentialData;if(!data||data.totalFindings===0)return '<div class="card"><div class="empty-state">No hardcoded credentials found. Your project is clean.</div></div>';var h='<div class="section-intro">Hardcoded credentials in source code are the #1 cause of security breaches in AI projects. Keys pushed to git are scraped by bots within minutes. Findings below are grouped by credential type.</div>';h+='<div class="stats-grid">';h+=statCard(data.totalFindings,'Total Findings',data.totalFindings>0?'var(--red)':'var(--green)');h+=statCard(data.bySeverity.critical||0,'Critical',(data.bySeverity.critical||0)>0?'var(--critical)':'var(--text)');h+=statCard(data.bySeverity.high||0,'High',(data.bySeverity.high||0)>0?'var(--high)':'var(--text)');h+=statCard(data.bySeverity.medium||0,'Medium',(data.bySeverity.medium||0)>0?'var(--medium)':'var(--text)');h+='</div>';var matches=data.matches||[];var grouped={};for(var i=0;i<matches.length;i++){var m=matches[i];var key=m.findingId||m.title;if(!grouped[key]){grouped[key]={finding:m,files:[],count:0}}grouped[key].count++;grouped[key].files.push(m.filePath+(m.line?':'+m.line:''))}var sevOrder={critical:0,high:1,medium:2,low:3};var groups=Object.values(grouped).sort(function(a,b){return(sevOrder[a.finding.severity]||9)-(sevOrder[b.finding.severity]||9)});h+='<h2 class="section-title">Credential Findings ('+groups.length+' types across '+data.totalFindings+' files)<button class="export-btn" onclick="exportCsv("credentials")">Export CSV</button></h2>';h+='<table class="data-table" style="display:none"><thead><tr><th>ID</th><th>Title</th><th>Severity</th><th>Env Var</th><th>Occurrences</th><th>Files</th></tr></thead><tbody>';for(var i=0;i<groups.length;i++){var g=groups[i];var m=g.finding;h+='<tr><td>'+esc(m.findingId)+'</td><td>'+esc(m.title)+'</td><td>'+esc(m.severity)+'</td><td>'+esc(m.envVar)+'</td><td>'+g.count+'</td><td>'+g.files.join('; ')+'</td></tr>'}h+='</tbody></table>';for(var i=0;i<groups.length;i++){var g=groups[i];var m=g.finding;h+='<div class="cred-card"><div class="cred-card-header"><span class="sev-badge sev-'+esc(m.severity)+'">'+esc(m.severity)+'</span><span class="cred-card-title">'+esc(m.title)+'</span><span style="color:var(--dim);font-size:12px">'+esc(m.findingId)+' — '+g.count+' occurrence'+(g.count>1?'s':'')+'</span></div><div class="cred-card-meta"><div><div class="cred-card-meta-label">Migrate to</div><div class="cred-card-meta-value env">'+esc(m.envVar)+'</div></div></div>';if(m.explanation||m.businessImpact){h+='<div class="cred-card-detail">';if(m.explanation)h+='<div class="cred-card-detail-label">Why this matters</div><div class="cred-card-detail-text">'+esc(m.explanation)+'</div>';if(m.businessImpact)h+='<div class="cred-card-detail-label">Business impact</div><div class="cred-card-detail-text">'+esc(m.businessImpact)+'</div>';h+='</div>'}var showFiles=g.files.slice(0,5);h+='<div style="padding:8px 12px;font-size:11px;color:var(--dim);border-top:1px solid rgba(51,65,85,0.3)">';for(var j=0;j<showFiles.length;j++){h+=esc(showFiles[j])+'<br>'}if(g.count>5){h+='<span class="expand-toggle" onclick="toggleExpand(this)">+ '+(g.count-5)+' more files</span><div class="file-list-full">';for(var j=5;j<g.files.length;j++){h+=esc(g.files[j])+'<br>'}h+='</div>'}h+='</div></div>'}if(data.driftFindings&&data.driftFindings.length>0){var driftGrouped={};for(var i=0;i<data.driftFindings.length;i++){var d=data.driftFindings[i];var key=d.findingId||'drift';if(!driftGrouped[key]){driftGrouped[key]={finding:d,count:0,files:[]}}driftGrouped[key].count++;driftGrouped[key].files.push(d.filePath+(d.line?':'+d.line:''))}var driftGroups=Object.values(driftGrouped);h+='<h2 class="section-title">Scope Drift ('+driftGroups.length+' types)</h2><div class="card"><p style="color:var(--muted);font-size:12px;margin-bottom:8px;line-height:1.5">Scope drift occurs when a key provisioned for one service silently grants access to AI services.</p><table class="data-table"><thead><tr><th>ID</th><th>Occurrences</th><th>Sample Files</th></tr></thead><tbody>';for(var i=0;i<driftGroups.length;i++){var dg=driftGroups[i];h+='<tr><td>'+esc(dg.finding.findingId)+'</td><td>'+dg.count+'</td><td style="font-size:11px;color:var(--muted)">'+dg.files.slice(0,3).map(function(f){return esc(f)}).join(', ')+(dg.count>3?' + '+(dg.count-3)+' more':'')+'</td></tr>'}h+='</tbody></table></div>'}h+='<h2 class="section-title">Remediation</h2><div class="card">'+cmdBlock('opena2a protect')+'<p style="color:var(--muted);font-size:12px;margin-top:8px">Migrate hardcoded credentials to environment variables or encrypted vault.</p></div>';return h}var hygieneDescriptions={'Credential scan':'Detects API keys and secrets hardcoded in source files','.gitignore':'Prevents sensitive files from being committed to version control','.env protection':'Ensures .env files (which store secrets) are excluded from git','Lock file':'Pins exact dependency versions to prevent supply chain attacks','Security config':'OpenA2A configuration enables automated security monitoring'};function findHygieneDesc(label){if(!label)return '';var lc=label.toLowerCase();for(var key in hygieneDescriptions){if(lc.indexOf(key.toLowerCase())>=0)return hygieneDescriptions[key];}return '';}function renderHygiene(){var init=report.initData;var h='<div class="section-intro">Project hygiene measures foundational security practices. These checks do not require any OpenA2A tools -- they are standard development practices that prevent accidental exposure.</div>';h+='<div class="stats-grid">';h+=statCard(init.trustScore+'/100','Trust Score',scoreColor(init.trustScore));h+=statCard(init.postureScore+'/100','Posture Score',scoreColor(init.postureScore));h+=statCard(init.riskLevel,'Risk Level',init.riskLevel==='SECURE'||init.riskLevel==='LOW'?'var(--green)':init.riskLevel==='MEDIUM'?'var(--medium)':'var(--red)');h+='</div>';h+='<div class="overview-top"><div class="gauge-card">'+gaugeCircle(init.trustScore,'out of 100')+'</div><div><h2 class="section-title">Hygiene Checks</h2><div class="card">';var checks=init.hygieneChecks||[];for(var i=0;i<checks.length;i++){var c=checks[i];var statusClr=c.status==='pass'?'var(--green)':c.status==='fail'?'var(--red)':c.status==='warn'?'var(--medium)':'var(--dim)';var desc=findHygieneDesc(c.label);h+='<div class="hygiene-row"><div><span class="hygiene-label">'+esc(c.label)+'</span>'+(desc?'<div class="check-desc">'+esc(desc)+'</div>':'')+'</div><span style="color:'+statusClr+'">'+esc(c.detail)+'</span></div>'}h+='</div></div></div>';h+='<div class="score-explainer"><div style="font-size:12px;color:var(--dim);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px">Trust Score Breakdown</div>';h+='<div style="display:grid;grid-template-columns:1fr auto auto;gap:4px 16px;font-size:12px;align-items:center">';h+='<div style="color:var(--muted)">Start</div><div></div><div style="color:var(--text);font-weight:600;text-align:right">100</div>';var deductions=[{label:'.gitignore',checkLabel:'.gitignore',penalty:-15},{label:'.env protection',checkLabel:'.env protection',penalty:-10},{label:'Lock file',checkLabel:'Lock file',penalty:-5},{label:'Security config',checkLabel:'Security config',penalty:5}];for(var i=0;i<deductions.length;i++){var d=deductions[i];var check=null;for(var j=0;j<checks.length;j++){if(checks[j].label===d.checkLabel){check=checks[j];break}}var applied=false;if(d.penalty>0){applied=check&&check.status==='pass'}else{applied=!check||check.status!=='pass'}if(applied){var clr=d.penalty>0?'var(--green)':'var(--red)';h+='<div style="color:var(--muted)">'+esc(d.label)+'</div><div style="font-size:11px;color:'+clr+'">'+(d.penalty>0?'applied':'deducted')+'</div><div style="color:'+clr+';text-align:right;font-weight:600">'+(d.penalty>0?'+':'')+d.penalty+'</div>'}else{h+='<div style="color:var(--dim);text-decoration:line-through">'+esc(d.label)+'</div><div style="font-size:11px;color:var(--green)">passed</div><div style="color:var(--dim);text-align:right">--</div>'}}h+='<div style="color:var(--text);font-weight:700;border-top:1px solid var(--card-border);padding-top:4px;margin-top:4px">Final</div><div style="border-top:1px solid var(--card-border);padding-top:4px;margin-top:4px"></div><div style="color:'+scoreColor(init.trustScore)+';font-weight:700;text-align:right;border-top:1px solid var(--card-border);padding-top:4px;margin-top:4px">'+init.trustScore+'</div>';h+='</div></div>';h+='<div class="stats-grid">';h+=statCard(init.activeTools+'/'+init.totalTools,'OpenA2A Tools Active','var(--primary)');var advLabel=init.advisoryCount>0?init.advisoryCount+' found':'0 found';h+=statCard(advLabel,'Advisories',init.advisoryCount>0?'var(--amber)':'var(--green)');h+='</div>';if(init.matchedPackages&&init.matchedPackages.length>0){h+='<div class="card"><div class="card-title">Affected Packages</div><div style="font-size:12px;color:var(--muted)">'+init.matchedPackages.map(function(p){return esc(p)}).join(', ')+'</div></div>'}else{h+='<div class="card" style="font-size:12px;color:var(--dim)">Advisories checked against project dependencies via the OpenA2A Registry. No matching advisories found.</div>'}var guard=report.guardData;if(guard){h+='<h2 class="section-title">Config Integrity</h2>';if(guard.signatureStatus==='valid'){h+='<div class="card"><div class="stats-grid">';h+=statCard('Active','ConfigGuard','var(--green)');h+=statCard(guard.filesMonitored,'Files Monitored','var(--primary)');h+=statCard(guard.tamperedFiles?guard.tamperedFiles.length:0,'Tampered',(guard.tamperedFiles&&guard.tamperedFiles.length>0)?'var(--red)':'var(--green)');h+='</div>';if(guard.tamperedFiles&&guard.tamperedFiles.length>0){h+='<div style="margin-top:8px"><div style="font-size:12px;color:var(--dim);margin-bottom:4px">Tampered files:</div>';for(var i=0;i<guard.tamperedFiles.length;i++){h+='<div style="font-size:12px;color:var(--red)">'+esc(guard.tamperedFiles[i])+'</div>'}h+=cmdBlock('opena2a guard diff && opena2a guard resign')+'</div>'}else{h+='<div style="font-size:12px;color:var(--muted);margin-top:4px">All monitored files have valid signatures.</div>'}h+='</div>'}else{h+='<div class="card"><div class="hygiene-row"><span class="hygiene-label">ConfigGuard</span><span style="color:var(--dim)">Not active — sign configs to detect unauthorized changes</span></div><div style="margin-top:4px">'+cmdBlock('opena2a guard sign')+'</div></div>'}}h+='<h2 class="section-title">Project Info</h2><div class="card"><div class="hygiene-row"><span class="hygiene-label">Project</span><span>'+esc(init.projectName||'unnamed')+'</span></div><div class="hygiene-row"><span class="hygiene-label">Type</span><span>'+esc(init.projectType)+'</span></div><div class="hygiene-row"><span class="hygiene-label">Version</span><span>'+esc(init.projectVersion||'--')+'</span></div></div>';return h}function renderShield(){var shield=report.shieldData;var h='<div class="section-intro">Shield is the unified security orchestration layer. It collects events from all OpenA2A tools into a tamper-evident log and classifies them into actionable findings.</div>';h+='<div class="stats-grid">';h+=statCard(shield.postureScore+'/100','Posture Score',scoreColor(shield.postureScore));h+=statCard(shield.eventCount,'Events (7d)','var(--primary)');h+=statCard(shield.classifiedFindings?shield.classifiedFindings.length:0,'Findings',shield.classifiedFindings&&shield.classifiedFindings.length>0?'var(--amber)':'var(--green)');h+=statCard(shield.policyLoaded?'Loaded':'None','Policy',shield.policyLoaded?'var(--green)':'var(--dim)');h+=statCard(shield.policyMode||'--','Mode','var(--muted)');h+=statCard(shield.integrityStatus||'healthy','Integrity',shield.integrityStatus==='healthy'?'var(--green)':'var(--red)');h+='</div>';var cf=shield.classifiedFindings||[];if(cf.length>0){h+='<h2 class="section-title">Classified Findings</h2><div class="card"><table class="data-table"><thead><tr><th>ID</th><th>Title</th><th>Severity</th><th>Count</th><th>Remediation</th></tr></thead><tbody>';for(var i=0;i<cf.length;i++){var f=cf[i];var badges='';if(f.finding.owaspAgentic)badges+='<span class="badge-owasp">'+esc(f.finding.owaspAgentic)+'</span>';if(f.finding.mitreAtlas)badges+='<span class="badge-mitre">'+esc(f.finding.mitreAtlas)+'</span>';h+='<tr><td>'+esc(f.finding.id)+'</td><td>'+esc(f.finding.title)+(badges?' '+badges:'')+'</td><td><span class="sev-badge sev-'+esc(f.finding.severity)+'">'+esc(f.finding.severity)+'</span></td><td>'+f.count+'</td><td>'+cmdBlock(f.finding.remediation)+'</td></tr>';if(f.finding.description)h+='<tr><td colspan="5" class="finding-desc">'+esc(f.finding.description)+'</td></tr>';}h+='</tbody></table></div>';}var arp=shield.arpStats;if(arp&&arp.totalEvents>0){h+='<h2 class="section-title">Runtime Protection (ARP)</h2><div class="card"><div class="arp-grid"><div class="arp-stat"><div class="arp-stat-value">'+arp.totalEvents+'</div><div class="arp-stat-label">Total Events</div></div><div class="arp-stat"><div class="arp-stat-value" style="color:var(--amber)">'+arp.anomalies+'</div><div class="arp-stat-label">Anomalies</div></div><div class="arp-stat"><div class="arp-stat-value" style="color:var(--red)">'+arp.violations+'</div><div class="arp-stat-label">Violations</div></div><div class="arp-stat"><div class="arp-stat-value">'+arp.processEvents+'</div><div class="arp-stat-label">Process</div></div><div class="arp-stat"><div class="arp-stat-value">'+arp.networkEvents+'</div><div class="arp-stat-label">Network</div></div><div class="arp-stat"><div class="arp-stat-value">'+arp.enforcements+'</div><div class="arp-stat-label">Enforcements</div></div></div></div>';}else{h+='<h2 class="section-title">Runtime Protection (ARP)</h2><div class="section-intro">ARP monitors process spawns, network connections, and file access in real time.</div><div class="card"><div class="empty-state">No ARP events in the last 7 days. Start runtime monitoring:</div>'+cmdBlock('opena2a runtime start')+'</div>';}if(!shield.policyLoaded){h+='<h2 class="section-title">Policy</h2><div class="cta-card"><div class="cta-title">No Security Policy</div><div class="cta-desc">Initialize Shield to enable adaptive security policy.</div>'+cmdBlock('opena2a shield init')+'</div>';}return h;}function renderHma(){var hma=report.hmaData;if(!hma||!hma.available){return '<div class="section-intro">HackMyAgent runs 147 security checks across 30 categories against AI agent setups, testing for credential exposure, prompt injection, tool misuse, and OWASP Top 10 for LLM vulnerabilities.</div><div class="cta-card"><div class="cta-title">HackMyAgent Not Installed</div><div class="cta-desc">Install HMA to run comprehensive security scans against your AI agent.</div>'+cmdBlock('npm install -g hackmyagent')+'<p style="color:var(--muted);font-size:13px;margin-top:12px;text-align:center">Then re-run: <code style="color:var(--primary)">opena2a review</code></p></div>'}function isCommand(s){if(!s)return false;var lc=s.trim().toLowerCase();return/^(hackmyagent|npx |npm |opena2a |git |run |curl |mkdir )/.test(lc)}function fixCell(f){if(!f.fix)return '<span style="color:var(--dim);font-size:11px">No fix available</span>';if(isCommand(f.fix))return cmdBlock(f.fix);var h='<div style="font-size:12px;color:var(--muted);line-height:1.4">'+esc(f.fix)+'</div>';if(f.category==='skill'||f.category==='supply'){h+='<div style="margin-top:4px">'+cmdBlock('hackmyagent check '+(f.sampleFiles&&f.sampleFiles[0]?esc(f.sampleFiles[0].split(':')[0]):'<skill-path>'))+'</div>'}return h}var h='<div class="section-intro">HackMyAgent scanned your project with 147+ security checks across 30 categories. Results below show unique issue types, grouped by check ID.</div>';h+='<div class="stats-grid">';h+=statCard(hma.score+'/'+hma.maxScore,'HMA Score',scoreColor(hma.score));h+=statCard(hma.totalChecks,'Total Checks','var(--primary)');h+=statCard(hma.failed,'Failed',hma.failed>0?'var(--red)':'var(--green)');h+=statCard(hma.passed,'Passed','var(--green)');h+='</div>';var bs=hma.bySeverity||{};h+='<h2 class="section-title">Severity Breakdown</h2><div class="stats-grid">';h+=statCard(bs.critical||0,'Critical',(bs.critical||0)>0?'var(--critical)':'var(--text)');h+=statCard(bs.high||0,'High',(bs.high||0)>0?'var(--high)':'var(--text)');h+=statCard(bs.medium||0,'Medium',(bs.medium||0)>0?'var(--medium)':'var(--text)');h+=statCard(bs.low||0,'Low','var(--text)');h+='</div>';var bc=hma.byCategory||{};var cats=Object.keys(bc).sort(function(a,b){return bc[b]-bc[a]});if(cats.length>0){h+='<h2 class="section-title">Categories</h2><div class="card">';var maxCat=bc[cats[0]]||1;for(var i=0;i<cats.length;i++){var c=cats[i];var pct=Math.round((bc[c]/maxCat)*100);h+='<div style="display:grid;grid-template-columns:100px 1fr 50px;align-items:center;gap:10px;padding:6px 0;border-bottom:1px solid rgba(51,65,85,0.3)"><div style="font-size:12px;color:var(--muted);text-transform:capitalize">'+esc(c)+'</div><div style="position:relative;height:6px;background:rgba(255,255,255,0.06);border-radius:3px;overflow:hidden"><div style="position:absolute;left:0;top:0;height:100%;width:'+pct+'%;background:var(--primary);border-radius:3px"></div></div><div style="text-align:right;font-size:13px;font-weight:600;color:var(--text)">'+bc[c]+'</div></div>'}h+='</div>'}var tf=hma.topFindings||[];if(tf.length>0){var showCount=Math.min(10,tf.length);h+='<h2 class="section-title">Issues by Check ('+tf.length+' unique)<button class="export-btn" onclick="exportCsv("hma")">Export CSV</button></h2><div class="card"><table class="data-table"><thead><tr><th>Check</th><th>Name</th><th>Severity</th><th>Category</th><th>Occurrences</th><th>Fix</th></tr></thead><tbody>';for(var i=0;i<tf.length;i++){var f=tf[i];var rowStyle=i>=showCount?'style="display:none" class="hma-extra-row"':'';var filesHtml='<div style="font-size:10px;color:var(--dim);margin-top:4px">';var showFiles=f.sampleFiles?f.sampleFiles.slice(0,3):[];for(var j=0;j<showFiles.length;j++){filesHtml+=esc(showFiles[j])+'<br>'}if(f.count>3&&f.sampleFiles){filesHtml+='<span class="expand-toggle" onclick="toggleExpand(this)">+ '+(f.count-3)+' more</span><div class="file-list-full">';for(var j=3;j<f.sampleFiles.length;j++){filesHtml+=esc(f.sampleFiles[j])+'<br>'}if(f.count>f.sampleFiles.length){filesHtml+='<span style="color:var(--dim)">('+(f.count-f.sampleFiles.length)+' not shown)</span>'}filesHtml+='</div>'}filesHtml+='</div>';h+='<tr '+rowStyle+'><td style="white-space:nowrap">'+esc(f.checkId)+'</td><td>'+esc(f.name)+'<div style="font-size:11px;color:var(--dim);margin-top:2px">'+esc(f.description)+'</div>'+((f.guidance||legacyRiskKb[f.checkId])?'<div style="font-size:11px;color:var(--amber);margin-top:4px;line-height:1.4">'+(f.guidance||legacyRiskKb[f.checkId])+'</div>':'')+'</td><td><span class="sev-badge sev-'+esc(f.severity)+'">'+esc(f.severity)+'</span></td><td style="text-transform:capitalize">'+esc(f.category)+'</td><td style="text-align:center"><span style="font-weight:700;font-size:15px">'+f.count+'</span>'+filesHtml+'</td><td>'+fixCell(f)+'</td></tr>'}h+='</tbody></table>';if(tf.length>showCount){h+='<div style="text-align:center;padding:10px"><button class="export-btn" onclick="toggleHmaRows(this)" style="float:none">+ Show all '+tf.length+' checks</button></div>'}h+='</div>'}h+='<h2 class="section-title">How to Fix These Issues</h2>';h+='<div class="card"><div class="card-title" style="color:var(--primary)">1. Credential Management</div><p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">If your skills or tools need access to API keys, database credentials, or cloud tokens, never store them in source files or .env files accessible to AI tools. Use a credential broker that provides keys on-demand with audit logging.</p>'+cmdBlock('npx secretless-ai init')+'<p style="color:var(--dim);font-size:11px;margin-top:4px">Secretless AI moves credentials out of AI-accessible context and provides them through a secure broker.</p></div>';h+='<div class="card"><div class="card-title" style="color:var(--primary)">2. Skill Verification</div><p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">Unsigned and unverified skills can be modified without detection. Sign your skills, verify publishers, and pin content hashes to detect tampering. Review any skill that requests filesystem, network, or credential access.</p>'+cmdBlock('hackmyagent check <skill-path>')+'<p style="color:var(--dim);font-size:11px;margin-top:4px">Inspects a skill file for dangerous patterns before installation.</p></div>';h+='<div class="card"><div class="card-title" style="color:var(--primary)">3. Supply Chain Protection</div><p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">Register skills with a trusted registry, enable version drift detection, and block known malicious patterns. The ClawHavoc campaign actively targets AI tool users through compromised skills.</p>'+cmdBlock('hackmyagent secure --fix')+'<p style="color:var(--dim);font-size:11px;margin-top:4px">Auto-fixes all fixable issues: creates .gitignore patterns, adds hash pins, and flags unverified publishers.</p></div>';h+='<div class="card"><div class="card-title" style="color:var(--primary)">4. Runtime Boundaries</div><p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">Enable sandbox execution, restrict elevated permissions, and monitor agent behavior at runtime. An agent with unrestricted access is one prompt injection away from full system compromise.</p>'+cmdBlock('opena2a runtime start')+'<p style="color:var(--dim);font-size:11px;margin-top:4px">Starts runtime protection: monitors process spawns, network connections, and file access.</p></div>';return h}function renderShadowAi(){var data=report.detectData;if(!data)return '<div class="card"><div class="empty-state">Shadow AI detection data not available.</div></div>';var capDescs={'filesystem':'Can read and write files','shell-access':'Can run commands on this computer','database':'Can read and modify databases','network':'Can make requests to external services','browser':'Can control a web browser','source-control':'Can access code repositories','messaging':'Can send messages','payments':'Can access payment systems','cloud-services':'Can access cloud infrastructure'};var h='<div class="section-intro">Shadow AI detection discovers AI agents running on this machine, MCP servers configured across all platforms, and AI configuration files in the project. It assesses governance posture and identifies gaps in identity, behavioral rules, and capability policies.</div>';var govScore=data.governanceScore;h+='<div class="stats-grid">';h+=statCard(govScore+'/100','Governance Score',scoreColor(govScore));h+=statCard(data.agents?data.agents.length:0,'AI Agents','var(--primary)');h+=statCard(data.mcpServers?data.mcpServers.length:0,'MCP Servers','var(--primary)');h+=statCard(data.aiConfigs?data.aiConfigs.length:0,'AI Configs','var(--primary)');h+='</div>';h+=governanceBanner(govScore,data.recoverablePoints);var agents=data.agents||[];var mcpServers=data.mcpServers||[];if(agents.length>0||mcpServers.length>0){h+='<h2 class="section-title">What This Means</h2><div class="card">';if(agents.length>0){var governed=0;for(var i=0;i<agents.length;i++){if(agents[i].governanceStatus==='governed')governed++;}var ungoverned=agents.length-governed;if(ungoverned===0){h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">Your '+(agents.length===1?'AI agent has':'AI agents have')+' governance in place. Actions are bounded by the rules you defined.</p>';}else if(governed>0){h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">'+agents.length+' AI tool'+(agents.length!==1?'s are':' is')+' running on this machine. '+governed+' '+(governed===1?'has':'have')+' governance rules, '+ungoverned+' '+(ungoverned===1?'does':'do')+' not.</p>';}else{h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">'+agents.length+' AI tool'+(agents.length!==1?'s are':' is')+' running without governance. There are no documented rules limiting what '+(agents.length===1?'it':'they')+' can do in this project.</p>';}}if(mcpServers.length>0){var verified=0;for(var i=0;i<mcpServers.length;i++){if(mcpServers[i].verified)verified++;}var unverified=mcpServers.length-verified;h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">'+mcpServers.length+' MCP server'+(mcpServers.length!==1?'s give':' gives')+' your AI agents additional capabilities (file access, database queries, API calls, etc.).</p>';if(unverified>0&&verified>0){h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">'+verified+' '+(verified===1?'has':'have')+' verified identities, '+unverified+' '+(unverified===1?'does':'do')+' not.</p>';}else if(unverified===mcpServers.length){h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">None have verified identities, so there is no tamper-evident record of which server version is installed.</p>';}}h+='</div>';}h+='<h2 class="section-title">Running AI Agents</h2>';if(agents.length===0){h+='<div class="card"><div class="empty-state">No AI agents detected on this machine.</div></div>';}else{h+='<div class="card"><table class="data-table"><thead><tr><th>Name</th><th>Identity</th><th>Governance</th></tr></thead><tbody>';for(var i=0;i<agents.length;i++){var a=agents[i];var idClr=a.identityStatus==='identified'?'var(--green)':'var(--medium)';var govClr=a.governanceStatus==='governed'?'var(--green)':'var(--medium)';h+='<tr><td>'+esc(a.name)+'</td><td style="color:'+idClr+'">'+esc(a.identityStatus)+'</td><td style="color:'+govClr+'">'+esc(a.governanceStatus)+'</td></tr>';}h+='</tbody></table></div>';}h+='<h2 class="section-title">MCP Servers</h2>';if(mcpServers.length===0){h+='<div class="card"><div class="empty-state">No MCP server configurations found.</div></div>';}else{var projectMcp=[];var globalMcp=[];for(var i=0;i<mcpServers.length;i++){if(mcpServers[i].source.indexOf('(project)')>=0)projectMcp.push(mcpServers[i]);else globalMcp.push(mcpServers[i]);}if(projectMcp.length>0){h+='<div class="card"><div class="card-title">Project-local ('+projectMcp.length+')</div><table class="data-table"><thead><tr><th>Name</th><th>Transport</th><th>Verified</th><th>Capabilities</th><th>Risk</th></tr></thead><tbody>';for(var i=0;i<projectMcp.length;i++){var s=projectMcp[i];var verStr=s.verified?'<span style="color:var(--green)">verified</span>':'<span style="color:var(--dim)">no</span>';var realCaps=(s.capabilities||[]).filter(function(c){return c!=='unknown';});var capsHtml='';for(var j=0;j<realCaps.length;j++){var desc=capDescs[realCaps[j]]||realCaps[j];capsHtml+='<div style="font-size:11px;color:var(--muted);margin:1px 0">'+esc(desc)+'</div>';}if(realCaps.length===0)capsHtml='<span style="color:var(--dim)">--</span>';h+='<tr><td>'+esc(s.name)+'</td><td>'+esc(s.transport)+'</td><td>'+verStr+'</td><td>'+capsHtml+'</td><td><span class="sev-badge sev-'+esc(s.risk)+'">'+esc(s.risk)+'</span></td></tr>';}h+='</tbody></table></div>';}if(globalMcp.length>0){h+='<div class="card"><div class="card-title">Machine-wide ('+globalMcp.length+')</div><table class="data-table"><thead><tr><th>Name</th><th>Source</th><th>Transport</th><th>Capabilities</th><th>Risk</th></tr></thead><tbody>';for(var i=0;i<globalMcp.length;i++){var s=globalMcp[i];var realCaps=(s.capabilities||[]).filter(function(c){return c!=='unknown';});var capsHtml='';for(var j=0;j<realCaps.length;j++){var desc=capDescs[realCaps[j]]||realCaps[j];capsHtml+='<div style="font-size:11px;color:var(--muted);margin:1px 0">'+esc(desc)+'</div>';}if(realCaps.length===0)capsHtml='<span style="color:var(--dim)">--</span>';h+='<tr><td>'+esc(s.name)+'</td><td style="font-size:11px;color:var(--dim)">'+esc(s.source)+'</td><td>'+esc(s.transport)+'</td><td>'+capsHtml+'</td><td><span class="sev-badge sev-'+esc(s.risk)+'">'+esc(s.risk)+'</span></td></tr>';}h+='</tbody></table></div>';}}var aiConfigs=data.aiConfigs||[];if(aiConfigs.length>0){h+='<h2 class="section-title">AI Config Files</h2><div class="card"><table class="data-table"><thead><tr><th>File</th><th>Tool</th><th>Risk</th><th>Details</th></tr></thead><tbody>';for(var i=0;i<aiConfigs.length;i++){var c=aiConfigs[i];var highlight=c.risk==='critical'||c.risk==='high';var rowStyle=highlight?'background:rgba(239,68,68,0.04)':'';h+='<tr style="'+rowStyle+'"><td>'+esc(c.file)+'</td><td>'+esc(c.tool)+'</td><td><span class="sev-badge sev-'+esc(c.risk)+'">'+esc(c.risk)+'</span></td><td style="font-size:12px;color:var(--muted)">'+esc(c.details)+'</td></tr>';}h+='</tbody></table></div>';}var findings=data.findings||[];if(findings.length>0){h+='<h2 class="section-title">Findings</h2>';for(var i=0;i<findings.length;i++){var f=findings[i];h+='<div class="card" style="margin-bottom:8px"><div style="display:flex;align-items:center;gap:8px;margin-bottom:8px"><span class="sev-badge sev-'+esc(f.severity)+'">'+esc(f.severity)+'</span><span style="font-size:14px;font-weight:600">'+esc(f.title)+'</span></div><p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:10px">'+esc(f.whyItMatters)+'</p>'+cmdBlock(f.remediation)+'</div>';}}if(agents.length===0&&mcpServers.length===0&&aiConfigs.length===0&&findings.length===0){h+='<div class="card"><div class="empty-state">No shadow AI detected. Your project has full governance coverage.</div></div>';}return h;}renderPage('overview');})();
|
|
156
|
+
(function(){var report=JSON.parse(document.getElementById('report-data').textContent);var pagesRendered={};function esc(s){return s==null?'':String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');}function scoreColor(s){return s>=90?'var(--green)':s>=70?'var(--primary)':s>=50?'var(--medium)':'var(--red)';}document.getElementById('main-nav').addEventListener('click',function(e){var btn=e.target.closest('.nav-tab');if(!btn)return;var pg=btn.getAttribute('data-page');document.querySelectorAll('.nav-tab').forEach(function(t){t.classList.toggle('active',t===btn);});document.querySelectorAll('.page').forEach(function(p){p.classList.toggle('active',p.id==='page-'+pg);});renderPage(pg);});function renderPage(pg){if(pagesRendered[pg])return;pagesRendered[pg]=true;var el=document.getElementById('page-'+pg);switch(pg){case 'overview':el.innerHTML=renderOverview();break;case 'credentials':el.innerHTML=renderCredentials();break;case 'hygiene':el.innerHTML=renderHygiene();break;case 'shield':el.innerHTML=renderShield();break;case 'hma':el.innerHTML=renderHma();break;case 'shadowai':el.innerHTML=renderShadowAi();break;}}window.toggleHmaRows=function(btn){var rows=document.querySelectorAll('.hma-extra-row');var hidden=rows[0]&&rows[0].style.display==='none';for(var i=0;i<rows.length;i++){rows[i].style.display=hidden?'':'none'}btn.textContent=hidden?'Show fewer':'+ Show all checks'};var legacyRiskKb={'SKILL-010':'When a skill reads .env files, it can steal API keys, database passwords, and cloud credentials. Attackers use this to access your accounts, billing, and infrastructure. If the skill is compromised or malicious, every secret in your environment is exposed.','SKILL-005':'Skills that access ~/.ssh, ~/.aws, or credential files can impersonate you across every service you use. A single compromised skill could access your servers, cloud accounts, and private repositories.','SKILL-012':'Accessing cryptocurrency wallets or seed phrases gives an attacker irreversible access to your funds. Unlike passwords, stolen crypto keys cannot be rotated or recovered.','SKILL-002':'Remote fetch-and-execute means the skill downloads code from the internet and runs it. The remote server can change that code at any time, turning a safe skill into a backdoor without any update on your end.','SKILL-004':'Writing files outside the sandbox lets a skill modify system configs, install malware, or overwrite other applications. This breaks the isolation boundary that protects your system.','SKILL-007':'ClickFix social engineering tricks users into copying and pasting malicious commands. The skill appears helpful while guiding users to compromise their own systems.','SKILL-006':'Data exfiltration patterns (base64 encoding + HTTP POST to external servers) are how stolen credentials and source code leave your machine. Even if detection catches the theft later, the data is already gone.','SKILL-011':'Browser data contains saved passwords, session tokens, and cookies. A skill with browser access can hijack your authenticated sessions across every website you use.','SKILL-008':'Reverse shells give an attacker a live terminal on your machine. They can run any command, install persistence, and pivot to other systems on your network.','HEARTBEAT-001':'Heartbeat URLs let skills phone home to external servers. Without verification, an attacker can redirect the heartbeat to a malicious server that sends new instructions to the skill.','HEARTBEAT-004':'Heartbeats requesting dangerous capabilities (shell access, filesystem write) can be remotely activated. The skill stays dormant until the heartbeat server tells it to act.','CONFIG-001':'Session files contain authentication tokens. If exposed, anyone with the file can impersonate your logged-in session without needing your password.','CONFIG-004':'Plaintext API keys in config files are the most common cause of credential breaches. Automated scrapers find them within minutes of a git push.','CONFIG-007':'Unrestricted elevated execution means AI agents can run any command with no approval. A prompt injection or compromised tool can escalate to full system access.','SUPPLY-003':'This skill matches patterns from known malicious campaigns. It may have been installed legitimately but contains code sequences associated with active threats.','SUPPLY-005':'This skill contacts IP addresses used by the ClawHavoc command-and-control infrastructure. This is a strong indicator of compromise.','SUPPLY-006':'References to known malware payload filenames indicate the skill may download or deploy malicious executables.','GIT-002':'Without .env, .pem, and .key in .gitignore, a single careless commit pushes your secrets to git history. Even if deleted later, secrets remain in git history forever.','SKILL-003':'Scheduled tasks run without user awareness. A malicious skill that installs a cron job or heartbeat can persist after the skill itself is removed.','HEARTBEAT-002':'Without hash pinning, a man-in-the-middle can modify heartbeat responses. The skill trusts whatever it receives, even if it has been tampered with.','HEARTBEAT-003':'Unsigned heartbeat files can be replaced by an attacker. A signed heartbeat proves it came from the original publisher and has not been modified.','CONFIG-006':'Auto-following untrusted agents means your system automatically trusts new agents without review. A malicious agent can join and immediately have access.','CONFIG-008':'Disabling the sandbox removes the primary defense against malicious tools. Every tool runs with full system access instead of restricted permissions.','SUPPLY-001':'Unverified publishers cannot be held accountable. Anyone can publish a skill claiming to be from a trusted organization.','SUPPLY-004':'Without an installed hash, you cannot detect if a skill has been modified after installation. A supply chain attacker can silently replace skill code.','SUPPLY-007':'Social engineering instructions that guide users to execute commands are a hallmark of the ClawHavoc campaign targeting AI tool users.','SUPPLY-008':'Password-protected archives bypass antivirus scanning. This is a standard malware distribution technique.','GIT-001':'Without .gitignore, every file in your project can be accidentally committed, including secrets, credentials, and private keys.','SKILL-001':'Unsigned skills cannot prove who created them or that they have not been tampered with. You are trusting code with no chain of custody.','SCAN-001':'Oversized files may be used to evade security scanning. Scanners skip large files, which attackers exploit to hide malicious content.','SUPPLY-002':'Skills not listed in a trusted registry have no community vetting. Anyone can distribute them without accountability.'};window.toggleExpand=function(el){var target=el.nextElementSibling;if(target){target.classList.toggle('open');el.textContent=target.classList.contains('open')?'collapse':'+ show all'}};window.exportCsv=function(tabName){var rows=[];var LF=String.fromCharCode(10);var table=document.querySelector('#page-'+tabName+' table.data-table');if(!table){return}var headers=[];table.querySelectorAll('thead th').forEach(function(th){headers.push(th.textContent.trim())});rows.push(headers.join(','));table.querySelectorAll('tbody tr').forEach(function(tr){var cells=[];tr.querySelectorAll('td').forEach(function(td){var t=td.textContent.trim().replace(/"/g,'""');cells.push('"'+t+'"')});if(cells.length>0)rows.push(cells.join(','))});var csv=rows[0];for(var i=1;i<rows.length;i++){csv+=LF+rows[i]}var blob=new Blob([csv],{type:'text/csv'});var a=document.createElement('a');a.href=URL.createObjectURL(blob);a.download='opena2a-review-'+tabName+'.csv';a.click()};window.copyCmd=function(btn){var cmd=btn.getAttribute('data-cmd');if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(cmd).then(function(){btn.textContent='OK';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},1500);});}else{var ta=document.createElement('textarea');ta.value=cmd;ta.style.position='fixed';ta.style.left='-9999px';document.body.appendChild(ta);ta.select();document.execCommand('copy');document.body.removeChild(ta);btn.textContent='OK';btn.classList.add('copied');setTimeout(function(){btn.textContent='Copy';btn.classList.remove('copied');},1500);}};window.goToTab=function(tab){var btn=document.querySelector('.nav-tab[data-page="'+tab+'"]');if(btn)btn.click();};function gaugeCircle(score,label){var sz=170,cx=sz/2,cy=sz/2,r=65,sw=10,circ=2*Math.PI*r;var pct=Math.max(0,Math.min(100,score))/100,dash=pct*circ,gap=circ-dash;var clr=score>=90?'#22c55e':score>=70?'#06b6d4':score>=50?'#eab308':'#ef4444';var s='<svg width="'+sz+'" height="'+sz+'" viewBox="0 0 '+sz+' '+sz+'">';s+='<circle cx="'+cx+'" cy="'+cy+'" r="'+r+'" fill="none" stroke="rgba(255,255,255,0.05)" stroke-width="'+sw+'"/>';s+='<circle cx="'+cx+'" cy="'+cy+'" r="'+r+'" fill="none" stroke="'+clr+'" stroke-width="'+sw+'" stroke-dasharray="'+dash+' '+gap+'" stroke-dashoffset="'+(circ*0.25)+'" stroke-linecap="round" transform="rotate(-90 '+cx+' '+cy+')"/>';s+='<text x="'+cx+'" y="'+(cy-6)+'" text-anchor="middle" dominant-baseline="middle" font-size="32" font-weight="700" fill="'+clr+'" font-family="var(--font)">'+score+'</text>';s+='<text x="'+cx+'" y="'+(cy+20)+'" text-anchor="middle" dominant-baseline="middle" font-size="14" font-weight="600" fill="'+clr+'" font-family="var(--font)">'+esc(label||('out of 100'))+'</text>';s+='</svg>';return s;}function cmdBlock(cmd){return '<div class="cmd-block"><span class="cmd-text">'+esc(cmd)+'</span><button class="copy-btn" data-cmd="'+esc(cmd)+'" onclick="copyCmd(this)">Copy</button></div>';}function statCard(value,label,color){return '<div class="stat-card"><div class="stat-value" style="color:'+color+'">'+esc(String(value))+'</div><div class="stat-label">'+esc(label)+'</div></div>';}function scoreBanner(score,recoverySummary){var clr=scoreColor(score);var h='<div class="score-banner"><div class="score-banner-num" style="color:'+clr+'">'+score+'</div><div class="score-banner-bar"><div class="score-banner-label"><span>Composite Score</span><span>'+score+'/100</span></div><div class="score-banner-track"><div class="score-banner-fill" style="width:'+score+'%;background:'+clr+'"></div></div></div>';if(recoverySummary&&recoverySummary.totalRecoverable>0){var recovBg=score>=70?'rgba(6,182,212,0.15)':score>=50?'rgba(234,179,8,0.15)':'rgba(239,68,68,0.15)';h+='<div class="score-banner-grade" style="color:'+clr+';background:'+recovBg+'">+'+recoverySummary.totalRecoverable+' recoverable</div>';}h+='</div>';return h;}function governanceBanner(score,recoverablePoints){var clr=scoreColor(score);var h='<div class="score-banner"><div class="score-banner-num" style="color:'+clr+'">'+score+'</div><div class="score-banner-bar"><div class="score-banner-label"><span>Governance Score</span><span>'+score+'/100</span></div><div class="score-banner-track"><div class="score-banner-fill" style="width:'+score+'%;background:'+clr+'"></div></div></div>';if(recoverablePoints>0){var projected=Math.min(100,score+recoverablePoints);var recovBg=score>=70?'rgba(6,182,212,0.15)':score>=50?'rgba(234,179,8,0.15)':'rgba(239,68,68,0.15)';h+='<div class="score-banner-grade" style="color:'+clr+';background:'+recovBg+'">path to '+projected+'</div>';}h+='</div>';return h;}var phaseDescriptions={'Project Scan':'Checks .gitignore, lock files, security config, and dependency advisories','Credentials':'Scans source files for hardcoded API keys, tokens, and secrets','Config Integrity':'Verifies cryptographic signatures on monitored config files','Shield Analysis':'Analyzes 7 days of security events, policy violations, and ARP detections','HMA Scan':'Runs HackMyAgent security checks against your AI agent endpoints','Shadow AI':'Detects AI agents, MCP servers, and AI configs; checks governance posture'};function phaseCard(phase){var statusCls='status-'+phase.status;var time=phase.status==='skip'?'--':(phase.durationMs/1000).toFixed(1)+'s';var desc=phaseDescriptions[phase.name]||'';return '<div class="phase-card"><div style="display:flex;justify-content:space-between;align-items:center"><div class="phase-name">'+esc(phase.name)+'</div><span class="status-badge '+statusCls+'">'+esc(phase.status)+'</span></div><div class="phase-detail">'+esc(phase.detail)+'</div>'+(desc?'<div class="phase-desc">'+esc(desc)+'</div>':'')+'<div class="phase-time">'+esc(time)+'</div></div>';}function renderOverview(){var h='';var sevCounts={critical:0,high:0,medium:0,low:0};var findings=report.findings||[];for(var i=0;i<findings.length;i++){var s=findings[i].severity;if(s in sevCounts)sevCounts[s]++;}h+=scoreBanner(report.compositeScore,report.recoverySummary);h+='<div class="stats-grid">';h+=statCard(findings.length,'Findings',findings.length>0?'var(--amber)':'var(--green)');h+=statCard(sevCounts.critical,'Critical',sevCounts.critical>0?'var(--critical)':'var(--text)');h+=statCard(sevCounts.high,'High',sevCounts.high>0?'var(--high)':'var(--text)');h+=statCard(sevCounts.medium,'Medium',sevCounts.medium>0?'var(--medium)':'var(--text)');h+='</div>';h+='<h2 class="section-title">Phase Results</h2><div class="phase-grid">';var phases=report.phases||[];for(var i=0;i<phases.length;i++)h+=phaseCard(phases[i]);h+='</div>';var detectScore=report.detectData?report.detectData.governanceScore:100;var dims=[{name:'Hygiene',weight:30,score:report.initData.trustScore,tab:'hygiene'},{name:'Shield',weight:20,score:report.shieldData.postureScore,tab:'shield'},{name:'Credentials',weight:20,score:phases.length>1?phases[1].score:0,tab:'credentials'},{name:'Integrity',weight:15,score:phases.length>2?phases[2].score:0,tab:'hygiene'},{name:'Shadow AI',weight:15,score:detectScore,tab:'shadowai'}];h+='<div class="score-explainer"><div style="font-size:12px;color:var(--dim);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:12px">Score Breakdown</div><div style="display:flex;flex-direction:column;gap:10px">';for(var i=0;i<dims.length;i++){var d=dims[i];var clr=scoreColor(d.score);h+='<div style="display:grid;grid-template-columns:100px 1fr 60px 50px;align-items:center;gap:10px;cursor:pointer" onclick="goToTab("'+d.tab+'")"><div style="display:flex;align-items:baseline;gap:6px"><span style="font-size:13px;color:var(--muted)">'+esc(d.name)+'</span></div><div style="position:relative;height:8px;background:rgba(255,255,255,0.06);border-radius:4px;overflow:hidden"><div style="position:absolute;left:0;top:0;height:100%;width:'+d.score+'%;background:'+clr+';border-radius:4px;transition:width 0.3s"></div></div><div style="text-align:right;font-size:14px;font-weight:700;color:'+clr+'">'+d.score+'<span style="font-size:11px;color:var(--dim);font-weight:400">/100</span></div><div style="text-align:right;font-size:11px;color:var(--dim)">x '+d.weight+'%</div></div>';}h+='</div><div style="display:flex;justify-content:space-between;align-items:center;border-top:1px solid rgba(51,65,85,0.4);margin-top:12px;padding-top:8px"><div style="display:flex;gap:12px;font-size:12px;color:var(--dim)"><span><strong style="color:var(--green)">A</strong> 90+</span><span><strong style="color:var(--primary)">B</strong> 80+</span><span><strong style="color:var(--medium)">C</strong> 70+</span><span><strong style="color:var(--high)">D</strong> 60+</span><span><strong style="color:var(--red)">F</strong> <60</span></div><div style="font-size:12px;color:var(--dim)">Click a row to view details</div></div></div>';var actions=report.actionItems||[];var actionImpact={'critical':'Immediate risk of credential compromise or data breach','high':'Significant security gap that attackers can exploit','medium':'Moderate risk that weakens your security posture','low':'Minor improvement to harden your defenses','info':'Recommended best practice'};if(actions.length>0){h+='<h2 class="section-title">Action Items</h2><div class="card">';for(var i=0;i<actions.length;i++){var a=actions[i];var impact=actionImpact[a.severity]||'';h+='<div class="action-item"><div class="action-priority">#'+a.priority+'</div><div class="action-content"><div class="action-desc"><span class="sev-badge sev-'+esc(a.severity)+'">'+esc(a.severity)+'</span> '+esc(a.description)+'</div>'+(impact?'<div class="check-desc">'+esc(impact)+'</div>':'')+cmdBlock(a.command)+'<span class="action-link" onclick="goToTab("'+esc(a.tab)+'")">View details</span></div></div>';}h+='</div>';}if(findings.length>0){h+='<h2 class="section-title">Findings</h2><div class="card"><table class="data-table"><thead><tr><th>ID</th><th>Title</th><th>Severity</th><th>Source</th><th>Detail</th></tr></thead><tbody>';var top=findings.slice(0,10);for(var i=0;i<top.length;i++){var f=top[i];h+='<tr><td>'+esc(f.id)+'</td><td>'+esc(f.title)+'</td><td><span class="sev-badge sev-'+esc(f.severity)+'">'+esc(f.severity)+'</span></td><td>'+esc(f.source)+'</td><td style="font-size:11px;color:var(--muted)">'+esc(f.detail)+'</td></tr>';}h+='</tbody></table></div>';}return h;}function renderCredentials(){var data=report.credentialData;if(!data||data.totalFindings===0)return '<div class="card"><div class="empty-state">No hardcoded credentials found. Your project is clean.</div></div>';var h='<div class="section-intro">Hardcoded credentials in source code are the #1 cause of security breaches in AI projects. Keys pushed to git are scraped by bots within minutes. Findings below are grouped by credential type.</div>';h+='<div class="stats-grid">';h+=statCard(data.totalFindings,'Total Findings',data.totalFindings>0?'var(--red)':'var(--green)');h+=statCard(data.bySeverity.critical||0,'Critical',(data.bySeverity.critical||0)>0?'var(--critical)':'var(--text)');h+=statCard(data.bySeverity.high||0,'High',(data.bySeverity.high||0)>0?'var(--high)':'var(--text)');h+=statCard(data.bySeverity.medium||0,'Medium',(data.bySeverity.medium||0)>0?'var(--medium)':'var(--text)');h+='</div>';var matches=data.matches||[];var grouped={};for(var i=0;i<matches.length;i++){var m=matches[i];var key=m.findingId||m.title;if(!grouped[key]){grouped[key]={finding:m,files:[],count:0}}grouped[key].count++;grouped[key].files.push(m.filePath+(m.line?':'+m.line:''))}var sevOrder={critical:0,high:1,medium:2,low:3};var groups=Object.values(grouped).sort(function(a,b){return(sevOrder[a.finding.severity]||9)-(sevOrder[b.finding.severity]||9)});h+='<h2 class="section-title">Credential Findings ('+groups.length+' types across '+data.totalFindings+' files)<button class="export-btn" onclick="exportCsv("credentials")">Export CSV</button></h2>';h+='<table class="data-table" style="display:none"><thead><tr><th>ID</th><th>Title</th><th>Severity</th><th>Env Var</th><th>Occurrences</th><th>Files</th></tr></thead><tbody>';for(var i=0;i<groups.length;i++){var g=groups[i];var m=g.finding;h+='<tr><td>'+esc(m.findingId)+'</td><td>'+esc(m.title)+'</td><td>'+esc(m.severity)+'</td><td>'+esc(m.envVar)+'</td><td>'+g.count+'</td><td>'+g.files.join('; ')+'</td></tr>'}h+='</tbody></table>';for(var i=0;i<groups.length;i++){var g=groups[i];var m=g.finding;h+='<div class="cred-card"><div class="cred-card-header"><span class="sev-badge sev-'+esc(m.severity)+'">'+esc(m.severity)+'</span><span class="cred-card-title">'+esc(m.title)+'</span><span style="color:var(--dim);font-size:12px">'+esc(m.findingId)+' — '+g.count+' occurrence'+(g.count>1?'s':'')+'</span></div><div class="cred-card-meta"><div><div class="cred-card-meta-label">Migrate to</div><div class="cred-card-meta-value env">'+esc(m.envVar)+'</div></div></div>';if(m.explanation||m.businessImpact){h+='<div class="cred-card-detail">';if(m.explanation)h+='<div class="cred-card-detail-label">Why this matters</div><div class="cred-card-detail-text">'+esc(m.explanation)+'</div>';if(m.businessImpact)h+='<div class="cred-card-detail-label">Business impact</div><div class="cred-card-detail-text">'+esc(m.businessImpact)+'</div>';h+='</div>'}var showFiles=g.files.slice(0,5);h+='<div style="padding:8px 12px;font-size:11px;color:var(--dim);border-top:1px solid rgba(51,65,85,0.3)">';for(var j=0;j<showFiles.length;j++){h+=esc(showFiles[j])+'<br>'}if(g.count>5){h+='<span class="expand-toggle" onclick="toggleExpand(this)">+ '+(g.count-5)+' more files</span><div class="file-list-full">';for(var j=5;j<g.files.length;j++){h+=esc(g.files[j])+'<br>'}h+='</div>'}h+='</div></div>'}if(data.driftFindings&&data.driftFindings.length>0){var driftGrouped={};for(var i=0;i<data.driftFindings.length;i++){var d=data.driftFindings[i];var key=d.findingId||'drift';if(!driftGrouped[key]){driftGrouped[key]={finding:d,count:0,files:[]}}driftGrouped[key].count++;driftGrouped[key].files.push(d.filePath+(d.line?':'+d.line:''))}var driftGroups=Object.values(driftGrouped);h+='<h2 class="section-title">Scope Drift ('+driftGroups.length+' types)</h2><div class="card"><p style="color:var(--muted);font-size:12px;margin-bottom:8px;line-height:1.5">Scope drift occurs when a key provisioned for one service silently grants access to AI services.</p><table class="data-table"><thead><tr><th>ID</th><th>Occurrences</th><th>Sample Files</th></tr></thead><tbody>';for(var i=0;i<driftGroups.length;i++){var dg=driftGroups[i];h+='<tr><td>'+esc(dg.finding.findingId)+'</td><td>'+dg.count+'</td><td style="font-size:11px;color:var(--muted)">'+dg.files.slice(0,3).map(function(f){return esc(f)}).join(', ')+(dg.count>3?' + '+(dg.count-3)+' more':'')+'</td></tr>'}h+='</tbody></table></div>'}h+='<h2 class="section-title">Remediation</h2><div class="card">'+cmdBlock('opena2a protect')+'<p style="color:var(--muted);font-size:12px;margin-top:8px">Migrate hardcoded credentials to environment variables or encrypted vault.</p></div>';return h}var hygieneDescriptions={'Credential scan':'Detects API keys and secrets hardcoded in source files','.gitignore':'Prevents sensitive files from being committed to version control','.env protection':'Ensures .env files (which store secrets) are excluded from git','Lock file':'Pins exact dependency versions to prevent supply chain attacks','Security config':'OpenA2A configuration enables automated security monitoring'};function findHygieneDesc(label){if(!label)return '';var lc=label.toLowerCase();for(var key in hygieneDescriptions){if(lc.indexOf(key.toLowerCase())>=0)return hygieneDescriptions[key];}return '';}function renderHygiene(){var init=report.initData;var h='<div class="section-intro">Project hygiene measures foundational security practices. These checks do not require any OpenA2A tools -- they are standard development practices that prevent accidental exposure.</div>';h+='<div class="stats-grid">';h+=statCard(init.trustScore+'/100','Trust Score',scoreColor(init.trustScore));h+=statCard(init.postureScore+'/100','Posture Score',scoreColor(init.postureScore));h+=statCard(init.riskLevel,'Risk Level',init.riskLevel==='SECURE'||init.riskLevel==='LOW'?'var(--green)':init.riskLevel==='MEDIUM'?'var(--medium)':'var(--red)');h+='</div>';h+='<div class="overview-top"><div class="gauge-card">'+gaugeCircle(init.trustScore,'out of 100')+'</div><div><h2 class="section-title">Hygiene Checks</h2><div class="card">';var checks=init.hygieneChecks||[];for(var i=0;i<checks.length;i++){var c=checks[i];var statusClr=c.status==='pass'?'var(--green)':c.status==='fail'?'var(--red)':c.status==='warn'?'var(--medium)':'var(--dim)';var desc=findHygieneDesc(c.label);h+='<div class="hygiene-row"><div><span class="hygiene-label">'+esc(c.label)+'</span>'+(desc?'<div class="check-desc">'+esc(desc)+'</div>':'')+'</div><span style="color:'+statusClr+'">'+esc(c.detail)+'</span></div>'}h+='</div></div></div>';h+='<div class="score-explainer"><div style="font-size:12px;color:var(--dim);text-transform:uppercase;letter-spacing:0.5px;margin-bottom:8px">Trust Score Breakdown</div>';h+='<div style="display:grid;grid-template-columns:1fr auto auto;gap:4px 16px;font-size:12px;align-items:center">';h+='<div style="color:var(--muted)">Start</div><div></div><div style="color:var(--text);font-weight:600;text-align:right">100</div>';var deductions=[{label:'.gitignore',checkLabel:'.gitignore',penalty:-15},{label:'.env protection',checkLabel:'.env protection',penalty:-10},{label:'Lock file',checkLabel:'Lock file',penalty:-5},{label:'Security config',checkLabel:'Security config',penalty:5}];for(var i=0;i<deductions.length;i++){var d=deductions[i];var check=null;for(var j=0;j<checks.length;j++){if(checks[j].label===d.checkLabel){check=checks[j];break}}var applied=false;if(d.penalty>0){applied=check&&check.status==='pass'}else{applied=!check||check.status!=='pass'}if(applied){var clr=d.penalty>0?'var(--green)':'var(--red)';h+='<div style="color:var(--muted)">'+esc(d.label)+'</div><div style="font-size:11px;color:'+clr+'">'+(d.penalty>0?'applied':'deducted')+'</div><div style="color:'+clr+';text-align:right;font-weight:600">'+(d.penalty>0?'+':'')+d.penalty+'</div>'}else{h+='<div style="color:var(--dim);text-decoration:line-through">'+esc(d.label)+'</div><div style="font-size:11px;color:var(--green)">passed</div><div style="color:var(--dim);text-align:right">--</div>'}}h+='<div style="color:var(--text);font-weight:700;border-top:1px solid var(--card-border);padding-top:4px;margin-top:4px">Final</div><div style="border-top:1px solid var(--card-border);padding-top:4px;margin-top:4px"></div><div style="color:'+scoreColor(init.trustScore)+';font-weight:700;text-align:right;border-top:1px solid var(--card-border);padding-top:4px;margin-top:4px">'+init.trustScore+'</div>';h+='</div></div>';h+='<div class="stats-grid">';h+=statCard(init.activeTools+'/'+init.totalTools,'OpenA2A Tools Active','var(--primary)');var advLabel=init.advisoryCount>0?init.advisoryCount+' found':'0 found';h+=statCard(advLabel,'Advisories',init.advisoryCount>0?'var(--amber)':'var(--green)');h+='</div>';if(init.matchedPackages&&init.matchedPackages.length>0){h+='<div class="card"><div class="card-title">Affected Packages</div><div style="font-size:12px;color:var(--muted)">'+init.matchedPackages.map(function(p){return esc(p)}).join(', ')+'</div></div>'}else{h+='<div class="card" style="font-size:12px;color:var(--dim)">Advisories checked against project dependencies via the OpenA2A Registry. No matching advisories found.</div>'}var guard=report.guardData;if(guard){h+='<h2 class="section-title">Config Integrity</h2>';if(guard.signatureStatus==='valid'){h+='<div class="card"><div class="stats-grid">';h+=statCard('Active','ConfigGuard','var(--green)');h+=statCard(guard.filesMonitored,'Files Monitored','var(--primary)');h+=statCard(guard.tamperedFiles?guard.tamperedFiles.length:0,'Tampered',(guard.tamperedFiles&&guard.tamperedFiles.length>0)?'var(--red)':'var(--green)');h+='</div>';if(guard.tamperedFiles&&guard.tamperedFiles.length>0){h+='<div style="margin-top:8px"><div style="font-size:12px;color:var(--dim);margin-bottom:4px">Tampered files:</div>';for(var i=0;i<guard.tamperedFiles.length;i++){h+='<div style="font-size:12px;color:var(--red)">'+esc(guard.tamperedFiles[i])+'</div>'}h+=cmdBlock('opena2a guard diff && opena2a guard resign')+'</div>'}else{h+='<div style="font-size:12px;color:var(--muted);margin-top:4px">All monitored files have valid signatures.</div>'}h+='</div>'}else{h+='<div class="card"><div class="hygiene-row"><span class="hygiene-label">ConfigGuard</span><span style="color:var(--dim)">Not active — sign configs to detect unauthorized changes</span></div><div style="margin-top:4px">'+cmdBlock('opena2a guard sign')+'</div></div>'}}h+='<h2 class="section-title">Project Info</h2><div class="card"><div class="hygiene-row"><span class="hygiene-label">Project</span><span>'+esc(init.projectName||'unnamed')+'</span></div><div class="hygiene-row"><span class="hygiene-label">Type</span><span>'+esc(init.projectType)+'</span></div><div class="hygiene-row"><span class="hygiene-label">Version</span><span>'+esc(init.projectVersion||'--')+'</span></div></div>';return h}function renderShield(){var shield=report.shieldData;var h='<div class="section-intro">Shield is the unified security orchestration layer. It collects events from all OpenA2A tools into a tamper-evident log and classifies them into actionable findings.</div>';h+='<div class="stats-grid">';h+=statCard(shield.postureScore+'/100','Posture Score',scoreColor(shield.postureScore));h+=statCard(shield.eventCount,'Events (7d)','var(--primary)');h+=statCard(shield.classifiedFindings?shield.classifiedFindings.length:0,'Findings',shield.classifiedFindings&&shield.classifiedFindings.length>0?'var(--amber)':'var(--green)');h+=statCard(shield.policyLoaded?'Loaded':'None','Policy',shield.policyLoaded?'var(--green)':'var(--dim)');h+=statCard(shield.policyMode||'--','Mode','var(--muted)');h+=statCard(shield.integrityStatus||'healthy','Integrity',shield.integrityStatus==='healthy'?'var(--green)':'var(--red)');h+='</div>';var cf=shield.classifiedFindings||[];if(cf.length>0){h+='<h2 class="section-title">Classified Findings</h2><div class="card"><table class="data-table"><thead><tr><th>ID</th><th>Title</th><th>Severity</th><th>Count</th><th>Remediation</th></tr></thead><tbody>';for(var i=0;i<cf.length;i++){var f=cf[i];var badges='';if(f.finding.owaspAgentic)badges+='<span class="badge-owasp">'+esc(f.finding.owaspAgentic)+'</span>';if(f.finding.mitreAtlas)badges+='<span class="badge-mitre">'+esc(f.finding.mitreAtlas)+'</span>';h+='<tr><td>'+esc(f.finding.id)+'</td><td>'+esc(f.finding.title)+(badges?' '+badges:'')+'</td><td><span class="sev-badge sev-'+esc(f.finding.severity)+'">'+esc(f.finding.severity)+'</span></td><td>'+f.count+'</td><td>'+cmdBlock(f.finding.remediation)+'</td></tr>';if(f.finding.description)h+='<tr><td colspan="5" class="finding-desc">'+esc(f.finding.description)+'</td></tr>';}h+='</tbody></table></div>';}var arp=shield.arpStats;if(arp&&arp.totalEvents>0){h+='<h2 class="section-title">Runtime Protection (ARP)</h2><div class="card"><div class="arp-grid"><div class="arp-stat"><div class="arp-stat-value">'+arp.totalEvents+'</div><div class="arp-stat-label">Total Events</div></div><div class="arp-stat"><div class="arp-stat-value" style="color:var(--amber)">'+arp.anomalies+'</div><div class="arp-stat-label">Anomalies</div></div><div class="arp-stat"><div class="arp-stat-value" style="color:var(--red)">'+arp.violations+'</div><div class="arp-stat-label">Violations</div></div><div class="arp-stat"><div class="arp-stat-value">'+arp.processEvents+'</div><div class="arp-stat-label">Process</div></div><div class="arp-stat"><div class="arp-stat-value">'+arp.networkEvents+'</div><div class="arp-stat-label">Network</div></div><div class="arp-stat"><div class="arp-stat-value">'+arp.enforcements+'</div><div class="arp-stat-label">Enforcements</div></div></div></div>';}else{h+='<h2 class="section-title">Runtime Protection (ARP)</h2><div class="section-intro">ARP monitors process spawns, network connections, and file access in real time.</div><div class="card"><div class="empty-state">No ARP events in the last 7 days. Start runtime monitoring:</div>'+cmdBlock('opena2a runtime start')+'</div>';}if(!shield.policyLoaded){h+='<h2 class="section-title">Policy</h2><div class="cta-card"><div class="cta-title">No Security Policy</div><div class="cta-desc">Initialize Shield to enable adaptive security policy.</div>'+cmdBlock('opena2a shield init')+'</div>';}return h;}function renderHma(){var hma=report.hmaData;if(!hma||!hma.available){return '<div class="section-intro">HackMyAgent runs 204 security checks across 30 categories against AI agent setups, testing for credential exposure, prompt injection, tool misuse, and OWASP Top 10 for LLM vulnerabilities.</div><div class="cta-card"><div class="cta-title">HackMyAgent Not Installed</div><div class="cta-desc">Install HMA to run comprehensive security scans against your AI agent.</div>'+cmdBlock('npm install -g hackmyagent')+'<p style="color:var(--muted);font-size:13px;margin-top:12px;text-align:center">Then re-run: <code style="color:var(--primary)">opena2a review</code></p></div>'}function isCommand(s){if(!s)return false;var lc=s.trim().toLowerCase();return/^(hackmyagent|npx |npm |opena2a |git |run |curl |mkdir )/.test(lc)}function fixCell(f){if(!f.fix)return '<span style="color:var(--dim);font-size:11px">No fix available</span>';if(isCommand(f.fix))return cmdBlock(f.fix);var h='<div style="font-size:12px;color:var(--muted);line-height:1.4">'+esc(f.fix)+'</div>';if(f.category==='skill'||f.category==='supply'){h+='<div style="margin-top:4px">'+cmdBlock('hackmyagent check '+(f.sampleFiles&&f.sampleFiles[0]?esc(f.sampleFiles[0].split(':')[0]):'<skill-path>'))+'</div>'}return h}var h='<div class="section-intro">HackMyAgent scanned your project with 204+ security checks across 30 categories. Results below show unique issue types, grouped by check ID.</div>';h+='<div class="stats-grid">';h+=statCard(hma.score+'/'+hma.maxScore,'HMA Score',scoreColor(hma.score));h+=statCard(hma.totalChecks,'Total Checks','var(--primary)');h+=statCard(hma.failed,'Failed',hma.failed>0?'var(--red)':'var(--green)');h+=statCard(hma.passed,'Passed','var(--green)');h+='</div>';var bs=hma.bySeverity||{};h+='<h2 class="section-title">Severity Breakdown</h2><div class="stats-grid">';h+=statCard(bs.critical||0,'Critical',(bs.critical||0)>0?'var(--critical)':'var(--text)');h+=statCard(bs.high||0,'High',(bs.high||0)>0?'var(--high)':'var(--text)');h+=statCard(bs.medium||0,'Medium',(bs.medium||0)>0?'var(--medium)':'var(--text)');h+=statCard(bs.low||0,'Low','var(--text)');h+='</div>';var bc=hma.byCategory||{};var cats=Object.keys(bc).sort(function(a,b){return bc[b]-bc[a]});if(cats.length>0){h+='<h2 class="section-title">Categories</h2><div class="card">';var maxCat=bc[cats[0]]||1;for(var i=0;i<cats.length;i++){var c=cats[i];var pct=Math.round((bc[c]/maxCat)*100);h+='<div style="display:grid;grid-template-columns:100px 1fr 50px;align-items:center;gap:10px;padding:6px 0;border-bottom:1px solid rgba(51,65,85,0.3)"><div style="font-size:12px;color:var(--muted);text-transform:capitalize">'+esc(c)+'</div><div style="position:relative;height:6px;background:rgba(255,255,255,0.06);border-radius:3px;overflow:hidden"><div style="position:absolute;left:0;top:0;height:100%;width:'+pct+'%;background:var(--primary);border-radius:3px"></div></div><div style="text-align:right;font-size:13px;font-weight:600;color:var(--text)">'+bc[c]+'</div></div>'}h+='</div>'}var tf=hma.topFindings||[];if(tf.length>0){var showCount=Math.min(10,tf.length);h+='<h2 class="section-title">Issues by Check ('+tf.length+' unique)<button class="export-btn" onclick="exportCsv("hma")">Export CSV</button></h2><div class="card"><table class="data-table"><thead><tr><th>Check</th><th>Name</th><th>Severity</th><th>Category</th><th>Occurrences</th><th>Fix</th></tr></thead><tbody>';for(var i=0;i<tf.length;i++){var f=tf[i];var rowStyle=i>=showCount?'style="display:none" class="hma-extra-row"':'';var filesHtml='<div style="font-size:10px;color:var(--dim);margin-top:4px">';var showFiles=f.sampleFiles?f.sampleFiles.slice(0,3):[];for(var j=0;j<showFiles.length;j++){filesHtml+=esc(showFiles[j])+'<br>'}if(f.count>3&&f.sampleFiles){filesHtml+='<span class="expand-toggle" onclick="toggleExpand(this)">+ '+(f.count-3)+' more</span><div class="file-list-full">';for(var j=3;j<f.sampleFiles.length;j++){filesHtml+=esc(f.sampleFiles[j])+'<br>'}if(f.count>f.sampleFiles.length){filesHtml+='<span style="color:var(--dim)">('+(f.count-f.sampleFiles.length)+' not shown)</span>'}filesHtml+='</div>'}filesHtml+='</div>';h+='<tr '+rowStyle+'><td style="white-space:nowrap">'+esc(f.checkId)+'</td><td>'+esc(f.name)+'<div style="font-size:11px;color:var(--dim);margin-top:2px">'+esc(f.description)+'</div>'+((f.guidance||legacyRiskKb[f.checkId])?'<div style="font-size:11px;color:var(--amber);margin-top:4px;line-height:1.4">'+(f.guidance||legacyRiskKb[f.checkId])+'</div>':'')+'</td><td><span class="sev-badge sev-'+esc(f.severity)+'">'+esc(f.severity)+'</span></td><td style="text-transform:capitalize">'+esc(f.category)+'</td><td style="text-align:center"><span style="font-weight:700;font-size:15px">'+f.count+'</span>'+filesHtml+'</td><td>'+fixCell(f)+'</td></tr>'}h+='</tbody></table>';if(tf.length>showCount){h+='<div style="text-align:center;padding:10px"><button class="export-btn" onclick="toggleHmaRows(this)" style="float:none">+ Show all '+tf.length+' checks</button></div>'}h+='</div>'}h+='<h2 class="section-title">How to Fix These Issues</h2>';h+='<div class="card"><div class="card-title" style="color:var(--primary)">1. Credential Management</div><p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">If your skills or tools need access to API keys, database credentials, or cloud tokens, never store them in source files or .env files accessible to AI tools. Use a credential broker that provides keys on-demand with audit logging.</p>'+cmdBlock('npx secretless-ai init')+'<p style="color:var(--dim);font-size:11px;margin-top:4px">Secretless AI moves credentials out of AI-accessible context and provides them through a secure broker.</p></div>';h+='<div class="card"><div class="card-title" style="color:var(--primary)">2. Skill Verification</div><p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">Unsigned and unverified skills can be modified without detection. Sign your skills, verify publishers, and pin content hashes to detect tampering. Review any skill that requests filesystem, network, or credential access.</p>'+cmdBlock('hackmyagent check <skill-path>')+'<p style="color:var(--dim);font-size:11px;margin-top:4px">Inspects a skill file for dangerous patterns before installation.</p></div>';h+='<div class="card"><div class="card-title" style="color:var(--primary)">3. Supply Chain Protection</div><p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">Register skills with a trusted registry, enable version drift detection, and block known malicious patterns. The ClawHavoc campaign actively targets AI tool users through compromised skills.</p>'+cmdBlock('hackmyagent secure --fix')+'<p style="color:var(--dim);font-size:11px;margin-top:4px">Auto-fixes all fixable issues: creates .gitignore patterns, adds hash pins, and flags unverified publishers.</p></div>';h+='<div class="card"><div class="card-title" style="color:var(--primary)">4. Runtime Boundaries</div><p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">Enable sandbox execution, restrict elevated permissions, and monitor agent behavior at runtime. An agent with unrestricted access is one prompt injection away from full system compromise.</p>'+cmdBlock('opena2a runtime start')+'<p style="color:var(--dim);font-size:11px;margin-top:4px">Starts runtime protection: monitors process spawns, network connections, and file access.</p></div>';return h}function renderShadowAi(){var data=report.detectData;if(!data)return '<div class="card"><div class="empty-state">Shadow AI detection data not available.</div></div>';var capDescs={'filesystem':'Can read and write files','shell-access':'Can run commands on this computer','database':'Can read and modify databases','network':'Can make requests to external services','browser':'Can control a web browser','source-control':'Can access code repositories','messaging':'Can send messages','payments':'Can access payment systems','cloud-services':'Can access cloud infrastructure'};var h='<div class="section-intro">Shadow AI detection discovers AI agents running on this machine, MCP servers configured across all platforms, and AI configuration files in the project. It assesses governance posture and identifies gaps in identity, behavioral rules, and capability policies.</div>';var govScore=data.governanceScore;h+='<div class="stats-grid">';h+=statCard(govScore+'/100','Governance Score',scoreColor(govScore));h+=statCard(data.agents?data.agents.length:0,'AI Agents','var(--primary)');h+=statCard(data.mcpServers?data.mcpServers.length:0,'MCP Servers','var(--primary)');h+=statCard(data.aiConfigs?data.aiConfigs.length:0,'AI Configs','var(--primary)');h+='</div>';h+=governanceBanner(govScore,data.recoverablePoints);var agents=data.agents||[];var mcpServers=data.mcpServers||[];if(agents.length>0||mcpServers.length>0){h+='<h2 class="section-title">What This Means</h2><div class="card">';if(agents.length>0){var governed=0;for(var i=0;i<agents.length;i++){if(agents[i].governanceStatus==='governed')governed++;}var ungoverned=agents.length-governed;if(ungoverned===0){h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">Your '+(agents.length===1?'AI agent has':'AI agents have')+' governance in place. Actions are bounded by the rules you defined.</p>';}else if(governed>0){h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">'+agents.length+' AI tool'+(agents.length!==1?'s are':' is')+' running on this machine. '+governed+' '+(governed===1?'has':'have')+' governance rules, '+ungoverned+' '+(ungoverned===1?'does':'do')+' not.</p>';}else{h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">'+agents.length+' AI tool'+(agents.length!==1?'s are':' is')+' running without governance. There are no documented rules limiting what '+(agents.length===1?'it':'they')+' can do in this project.</p>';}}if(mcpServers.length>0){var verified=0;for(var i=0;i<mcpServers.length;i++){if(mcpServers[i].verified)verified++;}var unverified=mcpServers.length-verified;h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">'+mcpServers.length+' MCP server'+(mcpServers.length!==1?'s give':' gives')+' your AI agents additional capabilities (file access, database queries, API calls, etc.).</p>';if(unverified>0&&verified>0){h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">'+verified+' '+(verified===1?'has':'have')+' verified identities, '+unverified+' '+(unverified===1?'does':'do')+' not.</p>';}else if(unverified===mcpServers.length){h+='<p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:8px">None have verified identities, so there is no tamper-evident record of which server version is installed.</p>';}}h+='</div>';}h+='<h2 class="section-title">Running AI Agents</h2>';if(agents.length===0){h+='<div class="card"><div class="empty-state">No AI agents detected on this machine.</div></div>';}else{h+='<div class="card"><table class="data-table"><thead><tr><th>Name</th><th>Identity</th><th>Governance</th></tr></thead><tbody>';for(var i=0;i<agents.length;i++){var a=agents[i];var idClr=a.identityStatus==='identified'?'var(--green)':'var(--medium)';var govClr=a.governanceStatus==='governed'?'var(--green)':'var(--medium)';h+='<tr><td>'+esc(a.name)+'</td><td style="color:'+idClr+'">'+esc(a.identityStatus)+'</td><td style="color:'+govClr+'">'+esc(a.governanceStatus)+'</td></tr>';}h+='</tbody></table></div>';}h+='<h2 class="section-title">MCP Servers</h2>';if(mcpServers.length===0){h+='<div class="card"><div class="empty-state">No MCP server configurations found.</div></div>';}else{var projectMcp=[];var globalMcp=[];for(var i=0;i<mcpServers.length;i++){if(mcpServers[i].source.indexOf('(project)')>=0)projectMcp.push(mcpServers[i]);else globalMcp.push(mcpServers[i]);}if(projectMcp.length>0){h+='<div class="card"><div class="card-title">Project-local ('+projectMcp.length+')</div><table class="data-table"><thead><tr><th>Name</th><th>Transport</th><th>Verified</th><th>Capabilities</th><th>Risk</th></tr></thead><tbody>';for(var i=0;i<projectMcp.length;i++){var s=projectMcp[i];var verStr=s.verified?'<span style="color:var(--green)">verified</span>':'<span style="color:var(--dim)">no</span>';var realCaps=(s.capabilities||[]).filter(function(c){return c!=='unknown';});var capsHtml='';for(var j=0;j<realCaps.length;j++){var desc=capDescs[realCaps[j]]||realCaps[j];capsHtml+='<div style="font-size:11px;color:var(--muted);margin:1px 0">'+esc(desc)+'</div>';}if(realCaps.length===0)capsHtml='<span style="color:var(--dim)">--</span>';h+='<tr><td>'+esc(s.name)+'</td><td>'+esc(s.transport)+'</td><td>'+verStr+'</td><td>'+capsHtml+'</td><td><span class="sev-badge sev-'+esc(s.risk)+'">'+esc(s.risk)+'</span></td></tr>';}h+='</tbody></table></div>';}if(globalMcp.length>0){h+='<div class="card"><div class="card-title">Machine-wide ('+globalMcp.length+')</div><table class="data-table"><thead><tr><th>Name</th><th>Source</th><th>Transport</th><th>Capabilities</th><th>Risk</th></tr></thead><tbody>';for(var i=0;i<globalMcp.length;i++){var s=globalMcp[i];var realCaps=(s.capabilities||[]).filter(function(c){return c!=='unknown';});var capsHtml='';for(var j=0;j<realCaps.length;j++){var desc=capDescs[realCaps[j]]||realCaps[j];capsHtml+='<div style="font-size:11px;color:var(--muted);margin:1px 0">'+esc(desc)+'</div>';}if(realCaps.length===0)capsHtml='<span style="color:var(--dim)">--</span>';h+='<tr><td>'+esc(s.name)+'</td><td style="font-size:11px;color:var(--dim)">'+esc(s.source)+'</td><td>'+esc(s.transport)+'</td><td>'+capsHtml+'</td><td><span class="sev-badge sev-'+esc(s.risk)+'">'+esc(s.risk)+'</span></td></tr>';}h+='</tbody></table></div>';}}var aiConfigs=data.aiConfigs||[];if(aiConfigs.length>0){h+='<h2 class="section-title">AI Config Files</h2><div class="card"><table class="data-table"><thead><tr><th>File</th><th>Tool</th><th>Risk</th><th>Details</th></tr></thead><tbody>';for(var i=0;i<aiConfigs.length;i++){var c=aiConfigs[i];var highlight=c.risk==='critical'||c.risk==='high';var rowStyle=highlight?'background:rgba(239,68,68,0.04)':'';h+='<tr style="'+rowStyle+'"><td>'+esc(c.file)+'</td><td>'+esc(c.tool)+'</td><td><span class="sev-badge sev-'+esc(c.risk)+'">'+esc(c.risk)+'</span></td><td style="font-size:12px;color:var(--muted)">'+esc(c.details)+'</td></tr>';}h+='</tbody></table></div>';}var findings=data.findings||[];if(findings.length>0){h+='<h2 class="section-title">Findings</h2>';for(var i=0;i<findings.length;i++){var f=findings[i];h+='<div class="card" style="margin-bottom:8px"><div style="display:flex;align-items:center;gap:8px;margin-bottom:8px"><span class="sev-badge sev-'+esc(f.severity)+'">'+esc(f.severity)+'</span><span style="font-size:14px;font-weight:600">'+esc(f.title)+'</span></div><p style="color:var(--muted);font-size:13px;line-height:1.6;margin-bottom:10px">'+esc(f.whyItMatters)+'</p>'+cmdBlock(f.remediation)+'</div>';}}if(agents.length===0&&mcpServers.length===0&&aiConfigs.length===0&&findings.length===0){h+='<div class="card"><div class="empty-state">No shadow AI detected. Your project has full governance coverage.</div></div>';}return h;}renderPage('overview');})();
|
|
157
157
|
</script>
|
|
158
158
|
</body>
|
|
159
159
|
</html>`;
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Extended SkillGuard checks (SKILL-
|
|
2
|
+
* Extended SkillGuard checks (SKILL-020 through SKILL-024).
|
|
3
3
|
*
|
|
4
|
-
* These complement the base SkillGuard plugin in hackmyagent
|
|
5
|
-
* frontmatter validation, overprivileged permissions,
|
|
6
|
-
* obfuscated code, and unbounded tool chaining.
|
|
4
|
+
* These complement the base SkillGuard plugin in hackmyagent (SKILL-001 through
|
|
5
|
+
* SKILL-019), adding checks for frontmatter validation, overprivileged permissions,
|
|
6
|
+
* env exfiltration, obfuscated code, and unbounded tool chaining.
|
|
7
|
+
*
|
|
8
|
+
* IDs start at 020 to avoid collision with HMA's existing SKILL checks:
|
|
9
|
+
* HMA SKILL-001 = Unsigned Skill
|
|
10
|
+
* HMA SKILL-003 = Heartbeat Installation
|
|
11
|
+
* HMA SKILL-007 = ClickFix Social Engineering
|
|
12
|
+
* HMA SKILL-009 = Typosquatting Name
|
|
13
|
+
* HMA SKILL-010 = Env File Exfiltration
|
|
7
14
|
*/
|
|
8
15
|
export interface SkillFinding {
|
|
9
16
|
id: string;
|
|
@@ -32,5 +39,5 @@ export declare function scanSkillDirectory(agentDir: string): SkillFinding[];
|
|
|
32
39
|
/**
|
|
33
40
|
* IDs of all checks implemented in this module.
|
|
34
41
|
*/
|
|
35
|
-
export declare const EXTENDED_SKILL_CHECK_IDS: readonly ["SKILL-
|
|
42
|
+
export declare const EXTENDED_SKILL_CHECK_IDS: readonly ["SKILL-020", "SKILL-021", "SKILL-022", "SKILL-023", "SKILL-024"];
|
|
36
43
|
//# sourceMappingURL=skillguard-checks.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skillguard-checks.d.ts","sourceRoot":"","sources":["../../src/scanners/skillguard-checks.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"skillguard-checks.d.ts","sourceRoot":"","sources":["../../src/scanners/skillguard-checks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,KAAK,CAAC;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAkDD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,MAAM,EAAE,CAkB/D;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,iBAAiB,CAuDnE;AA8KD;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CAkBhF;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CASnE;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,4EAM3B,CAAC"}
|
|
@@ -1,10 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* Extended SkillGuard checks (SKILL-
|
|
3
|
+
* Extended SkillGuard checks (SKILL-020 through SKILL-024).
|
|
4
4
|
*
|
|
5
|
-
* These complement the base SkillGuard plugin in hackmyagent
|
|
6
|
-
* frontmatter validation, overprivileged permissions,
|
|
7
|
-
* obfuscated code, and unbounded tool chaining.
|
|
5
|
+
* These complement the base SkillGuard plugin in hackmyagent (SKILL-001 through
|
|
6
|
+
* SKILL-019), adding checks for frontmatter validation, overprivileged permissions,
|
|
7
|
+
* env exfiltration, obfuscated code, and unbounded tool chaining.
|
|
8
|
+
*
|
|
9
|
+
* IDs start at 020 to avoid collision with HMA's existing SKILL checks:
|
|
10
|
+
* HMA SKILL-001 = Unsigned Skill
|
|
11
|
+
* HMA SKILL-003 = Heartbeat Installation
|
|
12
|
+
* HMA SKILL-007 = ClickFix Social Engineering
|
|
13
|
+
* HMA SKILL-009 = Typosquatting Name
|
|
14
|
+
* HMA SKILL-010 = Env File Exfiltration
|
|
8
15
|
*/
|
|
9
16
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
17
|
if (k2 === undefined) k2 = k;
|
|
@@ -160,13 +167,13 @@ function parseFrontmatter(content) {
|
|
|
160
167
|
return { raw, fields, valid: true, body };
|
|
161
168
|
}
|
|
162
169
|
// --- Check implementations ---
|
|
163
|
-
/** SKILL-
|
|
170
|
+
/** SKILL-020: Missing/invalid frontmatter */
|
|
164
171
|
function checkFrontmatter(filePath, content, relativePath) {
|
|
165
172
|
const findings = [];
|
|
166
173
|
const fm = parseFrontmatter(content);
|
|
167
174
|
if (!fm.valid) {
|
|
168
175
|
findings.push({
|
|
169
|
-
id: 'SKILL-
|
|
176
|
+
id: 'SKILL-020',
|
|
170
177
|
title: 'Missing YAML frontmatter',
|
|
171
178
|
description: `${relativePath}: Skill file lacks required YAML frontmatter (---). Add frontmatter with name, version, and capabilities fields.`,
|
|
172
179
|
severity: 'high',
|
|
@@ -178,7 +185,7 @@ function checkFrontmatter(filePath, content, relativePath) {
|
|
|
178
185
|
const missing = REQUIRED_FRONTMATTER_FIELDS.filter(f => !(f in fm.fields));
|
|
179
186
|
if (missing.length > 0) {
|
|
180
187
|
findings.push({
|
|
181
|
-
id: 'SKILL-
|
|
188
|
+
id: 'SKILL-020',
|
|
182
189
|
title: 'Incomplete frontmatter',
|
|
183
190
|
description: `${relativePath}: Missing required frontmatter fields: ${missing.join(', ')}. These are needed for capability declaration and version tracking.`,
|
|
184
191
|
severity: 'high',
|
|
@@ -188,7 +195,7 @@ function checkFrontmatter(filePath, content, relativePath) {
|
|
|
188
195
|
}
|
|
189
196
|
return findings;
|
|
190
197
|
}
|
|
191
|
-
/** SKILL-
|
|
198
|
+
/** SKILL-021: Overprivileged permissions (dangerous combos) */
|
|
192
199
|
function checkOverprivileged(filePath, content, relativePath) {
|
|
193
200
|
const findings = [];
|
|
194
201
|
const fm = parseFrontmatter(content);
|
|
@@ -199,7 +206,7 @@ function checkOverprivileged(filePath, content, relativePath) {
|
|
|
199
206
|
const hasSecond = capabilities.some(c => matchCapability(c, combo[1]));
|
|
200
207
|
if (hasFirst && hasSecond) {
|
|
201
208
|
findings.push({
|
|
202
|
-
id: 'SKILL-
|
|
209
|
+
id: 'SKILL-021',
|
|
203
210
|
title: 'Overprivileged permissions',
|
|
204
211
|
description: `${relativePath}: ${reason}. Restrict filesystem access to specific paths or remove outbound network access.`,
|
|
205
212
|
severity: 'high',
|
|
@@ -210,14 +217,14 @@ function checkOverprivileged(filePath, content, relativePath) {
|
|
|
210
217
|
}
|
|
211
218
|
return findings;
|
|
212
219
|
}
|
|
213
|
-
/** SKILL-
|
|
220
|
+
/** SKILL-022: Environment variable exfiltration */
|
|
214
221
|
function checkEnvExfiltration(filePath, content, relativePath) {
|
|
215
222
|
const findings = [];
|
|
216
223
|
const hasEnvAccess = ENV_ACCESS_PATTERNS.some(p => p.test(content));
|
|
217
224
|
const hasOutbound = OUTBOUND_PATTERNS.some(p => p.test(content));
|
|
218
225
|
if (hasEnvAccess && hasOutbound) {
|
|
219
226
|
findings.push({
|
|
220
|
-
id: 'SKILL-
|
|
227
|
+
id: 'SKILL-022',
|
|
221
228
|
title: 'Environment variable exfiltration risk',
|
|
222
229
|
description: `${relativePath}: Skill accesses environment variables AND has outbound network capability. This combination can exfiltrate secrets via network requests.`,
|
|
223
230
|
severity: 'critical',
|
|
@@ -227,13 +234,13 @@ function checkEnvExfiltration(filePath, content, relativePath) {
|
|
|
227
234
|
}
|
|
228
235
|
return findings;
|
|
229
236
|
}
|
|
230
|
-
/** SKILL-
|
|
237
|
+
/** SKILL-023: Obfuscated code patterns */
|
|
231
238
|
function checkObfuscation(filePath, content, relativePath) {
|
|
232
239
|
const findings = [];
|
|
233
240
|
for (const { pattern, label } of OBFUSCATION_PATTERNS) {
|
|
234
241
|
if (pattern.test(content)) {
|
|
235
242
|
findings.push({
|
|
236
|
-
id: 'SKILL-
|
|
243
|
+
id: 'SKILL-023',
|
|
237
244
|
title: 'Obfuscated code pattern',
|
|
238
245
|
description: `${relativePath}: Detected ${label}. Obfuscated code in skills can hide malicious behavior and should be reviewed.`,
|
|
239
246
|
severity: 'high',
|
|
@@ -245,7 +252,7 @@ function checkObfuscation(filePath, content, relativePath) {
|
|
|
245
252
|
}
|
|
246
253
|
return findings;
|
|
247
254
|
}
|
|
248
|
-
/** SKILL-
|
|
255
|
+
/** SKILL-024: Unbounded tool chaining */
|
|
249
256
|
function checkUnboundedChaining(filePath, content, relativePath) {
|
|
250
257
|
const findings = [];
|
|
251
258
|
const fm = parseFrontmatter(content);
|
|
@@ -260,7 +267,7 @@ function checkUnboundedChaining(filePath, content, relativePath) {
|
|
|
260
267
|
fm.raw.includes('iterationLimit'));
|
|
261
268
|
if (!hasMaxIterations) {
|
|
262
269
|
findings.push({
|
|
263
|
-
id: 'SKILL-
|
|
270
|
+
id: 'SKILL-024',
|
|
264
271
|
title: 'Unbounded tool chaining',
|
|
265
272
|
description: `${relativePath}: Skill declares tool:chain capability without maxIterations or iterationLimit. Unbounded chaining can lead to infinite loops or resource exhaustion.`,
|
|
266
273
|
severity: 'medium',
|
|
@@ -338,10 +345,10 @@ function scanSkillDirectory(agentDir) {
|
|
|
338
345
|
* IDs of all checks implemented in this module.
|
|
339
346
|
*/
|
|
340
347
|
exports.EXTENDED_SKILL_CHECK_IDS = [
|
|
341
|
-
'SKILL-
|
|
342
|
-
'SKILL-
|
|
343
|
-
'SKILL-
|
|
344
|
-
'SKILL-
|
|
345
|
-
'SKILL-
|
|
348
|
+
'SKILL-020',
|
|
349
|
+
'SKILL-021',
|
|
350
|
+
'SKILL-022',
|
|
351
|
+
'SKILL-023',
|
|
352
|
+
'SKILL-024',
|
|
346
353
|
];
|
|
347
354
|
//# sourceMappingURL=skillguard-checks.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skillguard-checks.js","sourceRoot":"","sources":["../../src/scanners/skillguard-checks.ts"],"names":[],"mappings":";AAAA
|
|
1
|
+
{"version":3,"file":"skillguard-checks.js","sourceRoot":"","sources":["../../src/scanners/skillguard-checks.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
{
|
|
3
3
|
"id": "scan",
|
|
4
4
|
"path": "opena2a scan",
|
|
5
|
-
"description": "Scan AI agent for security vulnerabilities using
|
|
5
|
+
"description": "Scan AI agent for security vulnerabilities using 204 checks",
|
|
6
6
|
"tags": ["security", "scan", "vulnerability", "hardening", "audit"],
|
|
7
7
|
"synonyms": ["check", "test", "analyze", "inspect", "review"],
|
|
8
8
|
"domains": ["mcp", "agent", "llm", "ai"],
|