Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions skills/ai-security/agent-security/agent-security.test.ts
Original file line number Diff line number Diff line change
@@ -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);
// ...
});
});
39 changes: 39 additions & 0 deletions skills/ai-security/agent-security/agent-security.ts
Original file line number Diff line number Diff line change
@@ -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) {
// ...
}
}
}
16 changes: 16 additions & 0 deletions skills/ai-security/agent-security/approvals.ts
Original file line number Diff line number Diff line change
@@ -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();

// ...
}
13 changes: 13 additions & 0 deletions skills/ai-security/agent-security/tools.ts
Original file line number Diff line number Diff line change
@@ -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();

// ...
}