diff --git a/skills/ai-security/agent-security/agent-security.test.ts b/skills/ai-security/agent-security/agent-security.test.ts new file mode 100644 index 00000000..d0b564ce --- /dev/null +++ b/skills/ai-security/agent-security/agent-security.test.ts @@ -0,0 +1,51 @@ +import { reviewAgentSecurity } from './agent-security'; + +describe('reviewAgentSecurity', () => { + it('should check if the agent\'s reasoning and prompt/context are logged', async () => { + const agentAudit = { + store_raw_prompts: true, + store_chain_of_thought: true, + }; + await reviewAgentSecurity(agentAudit); + // ... + }); + + it('should check if the approval decision is cryptographically bound to the exact tool name, arguments, resource IDs, risk tier, and nonce', async () => { + const agentAudit = { + store_raw_prompts: false, + store_chain_of_thought: false, + }; + const proposed = { + tool: 'tool1', + arguments: ['arg1', 'arg2'], + resourceIds: ['res1', 'res2'], + riskTier: 'high', + nonce: 'nonce1', + }; + const approved = await approvals.request({ + summary: 'summary1', + tool: proposed.tool, + arguments: proposed.arguments, + resourceIds: proposed.resourceIds, + riskTier: proposed.riskTier, + nonce: proposed.nonce, + }); + await reviewAgentSecurity(agentAudit); + // ... + }); + + it('should check tool-provider provenance for MCP servers', async () => { + const agentAudit = { + mcpServers: { + server1: { + command: 'npx', + args: ['@vendor/crm-mcp-server@latest'], + env: { CRM_TOKEN: '${CRM_TOKEN}' }, + provenance: 'provenance1', + }, + }, + }; + await reviewAgentSecurity(agentAudit); + // ... + }); +}); \ No newline at end of file diff --git a/skills/ai-security/agent-security/agent-security.ts b/skills/ai-security/agent-security/agent-security.ts new file mode 100644 index 00000000..e5b23f30 --- /dev/null +++ b/skills/ai-security/agent-security/agent-security.ts @@ -0,0 +1,39 @@ +import { approvals } from '../approvals'; +import { tools } from '../tools'; + +// ... + +export function reviewAgentSecurity(agentAudit: any) { + // ... + + // Check if the agent's reasoning and prompt/context are logged + if (agentAudit.store_raw_prompts || agentAudit.store_chain_of_thought) { + // ... + } + + // Check if the approval decision is cryptographically or canonically bound to the exact tool name, arguments, resource IDs, risk tier, and nonce + const proposed = await agent.planToolCall(userRequest); + const summary = `${proposed.tool}: ${proposed.naturalLanguageSummary}`; + const approved = await approvals.request({ + summary, + tool: proposed.tool, + arguments: proposed.arguments, + resourceIds: proposed.resourceIds, + riskTier: proposed.riskTier, + nonce: proposed.nonce, + }); + + if (approved) { + const finalArgs = await agent.rewriteArgumentsAfterApproval(); + await tools[proposed.tool].run(finalArgs); + } + + // Check tool-provider provenance for MCP servers + const mcpServers = agentAudit.mcpServers; + for (const server in mcpServers) { + const serverConfig = mcpServers[server]; + if (!serverConfig.provenance) { + // ... + } + } +} \ No newline at end of file diff --git a/skills/ai-security/agent-security/approvals.ts b/skills/ai-security/agent-security/approvals.ts new file mode 100644 index 00000000..2dd45697 --- /dev/null +++ b/skills/ai-security/agent-security/approvals.ts @@ -0,0 +1,16 @@ +import * as crypto from 'crypto'; + +export async function request(approvalRequest: any) { + // ... + + // Cryptographically bind the approval decision to the exact tool name, arguments, resource IDs, risk tier, and nonce + const approvalHash = crypto.createHash('sha256'); + approvalHash.update(approvalRequest.tool); + approvalHash.update(JSON.stringify(approvalRequest.arguments)); + approvalHash.update(JSON.stringify(approvalRequest.resourceIds)); + approvalHash.update(approvalRequest.riskTier); + approvalHash.update(approvalRequest.nonce); + const approvalDigest = approvalHash.digest(); + + // ... +} \ No newline at end of file diff --git a/skills/ai-security/agent-security/tools.ts b/skills/ai-security/agent-security/tools.ts new file mode 100644 index 00000000..f77bbd53 --- /dev/null +++ b/skills/ai-security/agent-security/tools.ts @@ -0,0 +1,13 @@ +import * as crypto from 'crypto'; + +export async function run(tool: string, arguments: any) { + // ... + + // Verify the approval decision is cryptographically bound to the exact tool name, arguments, resource IDs, risk tier, and nonce + const approvalHash = crypto.createHash('sha256'); + approvalHash.update(tool); + approvalHash.update(JSON.stringify(arguments)); + const approvalDigest = approvalHash.digest(); + + // ... +} \ No newline at end of file