Back to skill

Security audit

AgentGuard by Nano

Security checks for vulnerabilities and agentic risk

Overview

AgentGuard has a coherent security-tool purpose, but its artifacts contain serious implementation and documentation gaps that could expose credentials or bypass approval controls.

Review carefully before installing. Do not use this version for real secrets unless the default password is removed, approvals are authenticated, shell-based 1Password calls are replaced with safe argument-based execution, agent IDs are validated, and webhook/file-permission handling is tightened.

Vulnerability Patterns
  • Unauthorized Access and Privilege EscalationObtains permissions beyond the task's legitimate needs
  • Insecure DependenciesIntroduces malicious components through unsafe dependency sources
  • Insecure Skill Coding PracticesFinds exploitable flaws such as hardcoded secrets or command injection
  • Skill Instruction HijackingAlters the agent's session goals or safety constraints when the skill loads
  • Agent Memory PoisoningWrites attacker-controlled rules into memory that affect later sessions
Findings (9)

T09 · Insecure Skill Coding Practices

Error
Location
src/1password.js:43
Finding
Shell Command Injection in 1Password CLI Integration<![CDATA[ ## Vulnerability Details **File Location**: `src/1password.js:43-64`, with attacker-controlled command construction at `src/1password.js:112-188` and `src/1password.js:231-249` **Vulnerability Type**: OS command injection and secret disclosure through process arguments **Risk Level**: Critical ### Vulnerable Code ```javascript execOp(command, input = null) { const accountFlag = this.account ? ` --account ${this.account}` : ''; if (process.env.AGENTGUARD_USE_TMUX === 'true') { return this.execViaTmux(`op ${command}${accountFlag}`, input); } try { const options = { encoding: 'utf8', env: { ...process.env, OP_ACCOUNT: this.account } }; if (input) { options.input = input; } return execSync(`op ${command}${accountFlag}`, options); } catch (e) { throw new Error(`1Password CLI error: ${e.message}`); } } ``` Representative callers construct the command from externally supplied values: ```javascript let cmd = `item create --vault "${vault}" --category ${category} --title "${itemTitle}" "${field}=${value}"`; if (username) { cmd += ` --username "${username}"`; } if (url) { cmd += ` --url "${url}"`; } const result = this.execOp(cmd); ``` ### Technical Analysis `execSync()` executes the supplied string through a shell. The command incorporates account names, vault names, item titles, field names, usernames, URLs, references, agent IDs, credential keys, and secret values without shell-safe argument separation. Double quotes are not sufficient protection because shell substitutions such as `$(command)` and backticks remain active inside double-quoted strings. Some arguments, including `category` and `account`, are not consistently quoted at all. Credential values are also placed directly in process command lines, where they may be exposed through process inspection, shell diagnostics, or error messages. ### Attack Path 1. An attacker supplies a crafted agent ID, key, item title, account, vau ...[truncated 961 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Replace string-based `execSync()` calls with `execFileSync()` or `spawnSync()` using a fixed executable and an argument array. - Never invoke a shell for 1Password operations. - Pass credential values through stdin or another supported secret-input mechanism rather than command-line arguments. - Apply strict allowlist validation to account names, vault names, categories, agent IDs, and credential keys. - Do not include full child-process error messages if they could contain secrets. - Add tests using shell metacharacters, command substitutions, quotes, and newline characters to verify that inputs remain literal arguments. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/1password.js:70
Finding
Command Injection Through tmux Command Construction<![CDATA[ ## Vulnerability Details **File Location**: `src/1password.js:70-103` **Vulnerability Type**: Nested shell command injection **Risk Level**: Critical ### Vulnerable Code ```javascript execViaTmux(command, input = null) { const session = `op-${Date.now()}`; const socket = path.join(this.socketDir, `op-${Date.now()}.sock`); if (!fs.existsSync(this.socketDir)) { fs.mkdirSync(this.socketDir, { recursive: true }); } try { execSync(`tmux -S "${socket}" new -d -s ${session}`, { encoding: 'utf8' }); execSync(`tmux -S "${socket}" send-keys -t ${session} -- '${command}' Enter`, { encoding: 'utf8' }); execSync('sleep 2'); const output = execSync(`tmux -S "${socket}" capture-pane -p -J -t ${session} -S -200`, { encoding: 'utf8' }); execSync(`tmux -S "${socket}" kill-session -t ${session}`, { encoding: 'utf8' }); return output; } catch (e) { try { execSync(`tmux -S "${socket}" kill-session -t ${session} 2>/dev/null`); } catch {} throw new Error(`tmux execution error: ${e.message}`); } } ``` ### Technical Analysis When `AGENTGUARD_USE_TMUX=true`, a previously assembled 1Password command is embedded inside a single-quoted `tmux send-keys` shell command. An attacker-controlled apostrophe can terminate that quoting context and inject shell syntax. The configurable socket directory is also interpolated into several shell strings. In addition, sending commands through an interactive pane can leave command text and secret-bearing output in tmux history until cleanup succeeds. Error paths or process interruption may prevent complete cleanup. ### Attack Path 1. The tmux integration is enabled through `AGENTGUARD_USE_TMUX=true`. 2. An attacker supplies a value used in a 1Password command, such as an item title, credential value, key, or vault name. 3. The value introduces an apostrophe followed by shell syntax. 4. `execViaTmux()` embeds the resulting command within a single-quoted shell string. 5. The ...[truncated 485 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Remove shell-based `tmux send-keys` execution for security-sensitive commands. - Execute the `op` binary directly with a fixed executable path and an argument array. - If tmux is unavoidable, invoke `tmux` through `spawnSync()` with argument arrays and strictly validate socket and session identifiers. - Do not place secrets in interactive command text or tmux scrollback. - Ensure cleanup occurs in a `finally` block and remove socket artifacts after use. - Use restrictive permissions for any required socket directory. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
src/cli.js:24
Finding
Predictable Hard-Coded Fallback Vault Password<![CDATA[ ## Vulnerability Details **File Location**: `src/cli.js:24-27` **Vulnerability Type**: Hard-coded encryption secret **Risk Level**: High ### Vulnerable Code ```javascript // Get master password from env or prompt function getMasterPassword() { return process.env.AGENTGUARD_PASSWORD || 'default-password-change-me'; } ``` ### Technical Analysis When `AGENTGUARD_PASSWORD` is absent, all CLI-created vaults use the same publicly known password. Although PBKDF2 and AES-256-GCM are used elsewhere, those cryptographic controls cannot compensate for a universal, predictable master password. The fallback is silent, so users can create and populate a vault without realizing that it is protected by a known value. ### Attack Path 1. A user runs AgentGuard without setting `AGENTGUARD_PASSWORD`. 2. The CLI silently selects `default-password-change-me`. 3. Credentials are encrypted using a key derived from that known password and the stored salt. 4. An attacker obtains the `.vault` and `.salt` files through local access, backups, or another disclosure. 5. The attacker derives the same key and decrypts the credential container offline. ### Impact Assessment An attacker who obtains affected vault files can recover every credential stored in those files. The compromise is not limited to one credential and can affect API keys, OAuth tokens, and other secrets associated with each locally stored agent vault. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Remove the hard-coded fallback and fail closed when no master password or secure key source is available. - Prompt interactively without echo for CLI use, or generate a unique high-entropy key and store it in an operating-system keychain. - Enforce minimum password strength and reject the historical default value. - Detect vaults likely created with the default password and provide a secure key-rotation and re-encryption process. - Avoid relying solely on environment variables for long-lived production secrets. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/human-gate.js:110
Finding
Unauthenticated Approval of Dangerous Operations<![CDATA[ ## Vulnerability Details **File Location**: `src/human-gate.js:110-183`; exposed by `src/cli.js:229-259` **Vulnerability Type**: Missing authentication and authorization for security decisions **Risk Level**: High ### Vulnerable Code ```javascript async approve(requestId, approvedBy = 'owner') { const requestFile = path.join(this.pendingPath, `${requestId}.json`); if (!fs.existsSync(requestFile)) { throw new Error(`Request not found: ${requestId}`); } const request = JSON.parse(await readFile(requestFile, 'utf8')); if (new Date() > new Date(request.expiresAt)) { request.status = 'expired'; await writeFile(requestFile, JSON.stringify(request, null, 2)); throw new Error('Request has expired'); } if (request.status !== 'pending') { throw new Error(`Request already ${request.status}`); } request.status = 'approved'; request.response = { approved: true, approvedBy, respondedAt: new Date().toISOString() }; await writeFile(requestFile, JSON.stringify(request, null, 2)); return request; } ``` The CLI accepts an arbitrary identity label: ```javascript program .command('approve <requestId>') .description('Approve a pending request') .option('-b, --by <who>', 'Who approved', 'owner') .action(async (requestId, options) => { const guard = await createGuard(); const request = await guard.approveRequest(requestId, options.by); success(`Request approved: ${requestId}`); print(request); }); ``` ### Technical Analysis Approval is authorized solely by knowledge of the request ID. The `approvedBy` value is an unverified user-supplied string and provides no authentication. The implementation does not verify the registered owner, a signed approval token, a biometric assertion, a trusted callback signature, or the identity of the calling process. This conflicts with the documented human-gate security model because the stored transition from `pending` to `approved` is itself the ...[truncated 827 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require an authenticated, owner-bound approval assertion rather than a free-form identity string. - Use short-lived signed approval tokens that bind the request ID, owner, operation, agent ID, expiry, and intended decision. - Verify signatures on Feishu or other channel callbacks and validate callback audience and replay protection. - Restrict local approval commands to an authenticated administrative interface. - Store an immutable record of the verified approver identity and authentication method. - Apply strict permissions to pending request files and avoid exposing request IDs unnecessarily. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
src/vault-op.js:121
Finding
Path Traversal Through Unvalidated Agent Identifiers<![CDATA[ ## Vulnerability Details **File Location**: `src/vault-op.js:121-150`; related audit path construction at `src/audit.js:38-68` **Vulnerability Type**: Directory traversal and unintended file write **Risk Level**: High ### Vulnerable Code ```javascript const agentPath = path.join(this.vaultPath, `${agentId}.vault`); let credentials = {}; if (fs.existsSync(agentPath)) { credentials = await this.loadAll(agentId); } credentials[key] = { value, createdAt: credentials[key]?.createdAt || new Date().toISOString(), updatedAt: new Date().toISOString(), source: this.use1Password ? '1password+local' : 'local' }; let saltPath = path.join(this.vaultPath, `${agentId}.salt`); let salt; if (fs.existsSync(saltPath)) { salt = await readFile(saltPath); } else { salt = crypto.randomBytes(SALT_LENGTH); await writeFile(saltPath, salt); } const keyDerived = this.deriveKey(this.masterPassword, salt); const encrypted = this.encrypt(JSON.stringify(credentials), keyDerived); await writeFile(agentPath, encrypted); ``` Audit logging uses the same unvalidated identifier pattern: ```javascript const date = new Date().toISOString().split('T')[0]; const logFile = path.join(this.auditPath, `${agentId}-${date}.log`); ``` ### Technical Analysis Agent registration accepts arbitrary `agentId` strings, and those values are later incorporated directly into filesystem paths. An identifier containing `../` path components can cause normalized paths to escape the intended vault or audit directory. Appending `.vault`, `.salt`, or a date suffix limits the exact target filename but does not enforce directory containment. The same issue affects reads, writes, deletion-related vault updates, and audit creation. ### Attack Path 1. An attacker registers or otherwise supplies an agent ID containing traversal components such as `../../target`. 2. A credential storage or audit operation is performed for that agent. 3. `path.join()` normalizes the traversal components. 4. The ...[truncated 548 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Restrict agent IDs to a conservative allowlist, such as `^[A-Za-z0-9_-]{1,64}$`. - Use generated UUIDs or encoded identifiers as filenames instead of raw display IDs. - Resolve each destination path and verify that it begins with the resolved expected base directory plus the platform path separator. - Reject path separators, `.` components, null bytes, and platform-specific reserved names. - Apply the same validation to audit, vault, registry, and pending-request identifiers. - Add traversal tests for Unix and Windows path forms. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/human-gate.js:41
Finding
Sensitive Approval Records Created Without Explicit Restrictive Permissions<![CDATA[ ## Vulnerability Details **File Location**: `src/human-gate.js:23-24` and `src/human-gate.js:41-61` **Vulnerability Type**: Insecure storage of sensitive approval data **Risk Level**: Medium ### Vulnerable Code ```javascript async init() { await mkdir(this.pendingPath, { recursive: true }); } ``` ```javascript const request = { id: requestId, agentId, operation, details, status: 'pending', createdAt: new Date().toISOString(), expiresAt, response: null }; const requestFile = path.join(this.pendingPath, `${requestId}.json`); await writeFile(requestFile, JSON.stringify(request, null, 2)); ``` ### Technical Analysis Approval records may contain sensitive transaction data, message contents, API parameters, filenames, recipient information, and the request ID required by the unauthenticated approval mechanism. Neither directory creation nor file creation specifies restrictive modes, so effective permissions depend on the process umask and environment. The implementation also performs ordinary path-based writes without explicit protections against pre-existing symbolic links. ### Attack Path 1. An operation creates an approval request containing sensitive details. 2. The request is written as plaintext JSON using default filesystem permissions. 3. On a system with a permissive umask or shared data-directory access, another local user or process reads the record. 4. The attacker learns sensitive details and the request ID. 5. The disclosed request ID can facilitate exploitation of the unauthenticated approval weakness. ### Impact Assessment The issue can disclose sensitive operational metadata and approval identifiers to other local principals. In combination with missing approval authentication, disclosure may enable unauthorized approval of dangerous operations. The exact exposure depends on host permissions and umask configuration. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Create the AgentGuard data and pending directories with mode `0700`. - Create request files atomically with mode `0600` and exclusive-create semantics. - Reject or safely handle symbolic links and verify ownership before reading or replacing records. - Minimize persisted details and redact credentials, tokens, message bodies, and unnecessary personal data. - Consider encrypting approval records at rest. - Validate and repair permissions on existing AgentGuard directories during initialization. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/feishu-notifier.js:160
Finding
Unrestricted and Potentially Plaintext Webhook Delivery of Approval Details<![CDATA[ ## Vulnerability Details **File Location**: `src/feishu-notifier.js:160-207` **Vulnerability Type**: Sensitive data exposure and server-side request forgery risk **Risk Level**: Medium ### Vulnerable Code ```javascript async sendWebhook(payload) { return new Promise((resolve, reject) => { const url = new URL(this.webhookUrl); const client = url.protocol === 'https:' ? https : http; const data = JSON.stringify({ msg_type: 'interactive', card: payload }); const options = { hostname: url.hostname, port: url.port || (url.protocol === 'https:' ? 443 : 80), path: url.pathname, method: 'POST', headers: { 'Content-Type': 'application/json', 'Content-Length': data.length } }; const req = client.request(options, (res) => { let body = ''; res.on('data', chunk => body += chunk); res.on('end', () => { if (res.statusCode >= 200 && res.statusCode < 300) { resolve({ success: true, body }); } else { reject(new Error(`Webhook failed: ${res.statusCode} ${body}`)); } }); }); req.on('error', reject); req.write(data); req.end(); }); } ``` ### Technical Analysis The webhook URL may use either HTTP or HTTPS, and there is no hostname allowlist. Approval cards include serialized request details, so an HTTP URL exposes those details to network interception. If configuration is attacker-controlled, the process can also be directed to send POST requests to attacker-controlled or internal network endpoints. No request timeout, response-size limit, or destination-address validation is present. ### Attack Path 1. The webhook URL is configured as an HTTP endpoint, attacker-controlled host, or reachable internal service. 2. A dangerous operation creates an approval request. 3. The request details are embedded in the Feishu card payload. 4. `sendWebhook()` POSTs that data to the configured destinati ...[truncated 545 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Require HTTPS and reject all other protocols. - Allowlist documented official Feishu webhook hostnames. - Resolve destinations and reject loopback, private, link-local, multicast, and cloud metadata addresses. - Revalidate addresses across redirects, or disable redirects entirely. - Redact secrets and minimize approval details before transmission. - Add connection and overall request timeouts, response-size limits, and payload-size limits. - Avoid including untrusted response bodies in propagated errors. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
src/audit.js:16
Finding
Audit Logs Are Unkeyed and Use Shared Cross-Agent Chain State<![CDATA[ ## Vulnerability Details **File Location**: `src/audit.js:16-69` **Vulnerability Type**: Weak audit integrity design **Risk Level**: Medium ### Vulnerable Code ```javascript class Audit { constructor(auditPath) { this.auditPath = auditPath || path.join(process.env.HOME, '.agentguard', 'audit'); this.lastHash = null; } hash(prevHash, data) { const content = prevHash + JSON.stringify(data); return crypto.createHash('sha256').update(content).digest('hex'); } async log(agentId, operation, details = {}) { await this.init(); const date = new Date().toISOString().split('T')[0]; const logFile = path.join(this.auditPath, `${agentId}-${date}.log`); if (!this.lastHash && fs.existsSync(logFile)) { const lines = (await readFile(logFile, 'utf8')).trim().split('\n'); if (lines.length > 0) { const lastLine = JSON.parse(lines[lines.length - 1]); this.lastHash = lastLine.hash; } } const prevHash = this.lastHash || '0'.repeat(64); const entry = { timestamp: new Date().toISOString(), agentId, operation, details, prevHash }; entry.hash = this.hash(prevHash, entry); await appendFile(logFile, JSON.stringify(entry) + '\n'); this.lastHash = entry.hash; return entry; } } ``` ### Technical Analysis The chain uses plain SHA-256 without a secret key or digital signature. Anyone able to modify a log can alter an entry and recompute all subsequent hashes, so the mechanism does not provide authenticity against an attacker with file access. In addition, `lastHash` is a single object-wide value. Writes for different agents or dates can reuse another file's last hash, creating cross-file links that the per-file verification routine does not expect. This can cause integrity verification failures during normal multi-agent use. The implementation therefore does not substantiate the documentation's claim of cryptographically signed audit l ...[truncated 860 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Authenticate each entry with an HMAC or digital signature whose key is stored outside the audit directory. - Maintain chain state separately for each agent and log file, including date rotation. - Serialize writes or use locking to prevent concurrent chain races. - Anchor chain roots in an external trusted store or periodically publish signed checkpoints. - Apply restrictive permissions and append-only controls where supported. - Correct the documentation until genuine signed-log support is implemented. - Add tests covering multiple agents, date rollover, concurrent writes, truncation, deletion, and chain recomputation attempts. ]]>

T08 · Insecure Dependencies

Warning
Location
package-lock.json:24
Finding
Dependency Lockfile Uses a Non-Official Package Registry Mirror<![CDATA[ ## Vulnerability Details **File Location**: `package-lock.json:24` and `package-lock.json:33` **Vulnerability Type**: Unsafe dependency provenance **Risk Level**: Medium ### Vulnerable Code ```json "resolved": "https://registry.npmmirror.com/commander/-/commander-12.1.0.tgz" ``` ```json "resolved": "https://registry.npmmirror.com/uuid/-/uuid-9.0.1.tgz" ``` ### Technical Analysis The lockfile resolves runtime dependencies through `registry.npmmirror.com` rather than the official npm registry. Lockfile integrity hashes provide useful artifact verification, but the project still expands its supply-chain trust boundary to a third-party mirror. Future lockfile generation or dependency updates through that mirror can introduce provenance inconsistencies. No evidence in the reviewed files establishes that the mirror itself is malicious; the finding concerns avoidable third-party supply-chain exposure. ### Attack Path 1. A developer or build system performs installation using the committed lockfile. 2. Dependency artifacts are requested from the third-party mirror. 3. A compromise, misconfiguration, or inconsistent package publication at that mirror affects artifact delivery or future lockfile updates. 4. Unreviewed dependency code may enter the build or runtime environment if integrity metadata is also changed or regenerated. ### Impact Assessment A successful supply-chain compromise could execute malicious dependency code during application use or installation-related workflows. The current dependencies have no declared install scripts in the reviewed package metadata, but runtime compromise could still affect credential handling and all privileges available to AgentGuard. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Regenerate `package-lock.json` using `https://registry.npmjs.org/`. - Retain and verify lockfile integrity hashes in continuous integration. - Pin reviewed dependency versions and require review for lockfile changes. - Use automated vulnerability and provenance checks. - Restrict CI and release environments to approved registries. - Consider package signatures or provenance attestations where available. ]]>
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (74)

Tp4

High
Category
MCP Tool Poisoning
Confidence
93% confidence
Finding
The documentation claims permission scopes, human approval workflows, and audit trails, but the file itself does not provide a concrete policy model, enforcement architecture, or implementation evidence for those controls. For a credential-handling skill, incomplete or overstated security guarantees materially increase the risk of unauthorized secret use or unreviewed external actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documentation claims permission scopes, human approval workflows, and audit trails, but the file itself does not provide a concrete policy model, enforcement architecture, or implementation evidence for those controls. For a credential-handling skill, incomplete or overstated security guarantees materially increase the risk of unauthorized secret use or unreviewed external actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
99% confidence
Finding
The documentation claims permission scopes, human approval workflows, and audit trails, but the file itself does not provide a concrete policy model, enforcement architecture, or implementation evidence for those controls. For a credential-handling skill, incomplete or overstated security guarantees materially increase the risk of unauthorized secret use or unreviewed external actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding
The documentation claims permission scopes, human approval workflows, and audit trails, but the file itself does not provide a concrete policy model, enforcement architecture, or implementation evidence for those controls. For a credential-handling skill, incomplete or overstated security guarantees materially increase the risk of unauthorized secret use or unreviewed external actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding
The documentation claims permission scopes, human approval workflows, and audit trails, but the file itself does not provide a concrete policy model, enforcement architecture, or implementation evidence for those controls. For a credential-handling skill, incomplete or overstated security guarantees materially increase the risk of unauthorized secret use or unreviewed external actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding
The documentation claims permission scopes, human approval workflows, and audit trails, but the file itself does not provide a concrete policy model, enforcement architecture, or implementation evidence for those controls. For a credential-handling skill, incomplete or overstated security guarantees materially increase the risk of unauthorized secret use or unreviewed external actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
92% confidence
Finding
The documentation claims permission scopes, human approval workflows, and audit trails, but the file itself does not provide a concrete policy model, enforcement architecture, or implementation evidence for those controls. For a credential-handling skill, incomplete or overstated security guarantees materially increase the risk of unauthorized secret use or unreviewed external actions.

Tp4

High
Category
MCP Tool Poisoning
Confidence
90% confidence
Finding
The documentation claims permission scopes, human approval workflows, and audit trails, but the file itself does not provide a concrete policy model, enforcement architecture, or implementation evidence for those controls. For a credential-handling skill, incomplete or overstated security guarantees materially increase the risk of unauthorized secret use or unreviewed external actions.

Intent-Code Divergence

High
Confidence
99% confidence
Finding
The CLI silently falls back to a hardcoded master password when AGENTGUARD_PASSWORD is unset, which means all local secrets may be encrypted or protected with a publicly guessable value. In a credential-management tool, this defeats the core trust boundary because any user or malware aware of the default can access stored data.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The quick-start example shows a secret being passed directly on the command line (`agentguard vault store my-agent OPENAI_API_KEY sk-xxx`) without any warning or safer alternative. This can expose credentials through shell history, process listings, terminal logging, or copied documentation patterns, which is especially concerning in a skill centered on credential security.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
## Dangerous Operations

These operations always require human approval (unless policy is `auto-approve`):

- `send_message`, `send_email`
- `financial_transaction`
Confidence
86% confidence
Finding
The README states that dangerous operations always require human approval unless policy is set to `auto-approve`, which creates an explicit bypass for controls protecting high-risk actions such as credential access, external API calls, file writes, and command execution. In a trust middleware skill whose core purpose is enforcing permission boundaries and human oversight, allowing dangerous actions to be auto-approved weakens the security model and could enable fully autonomous sensitive or destructive behavior if misconfigured or abused.

Lp3

Medium
Category
MCP Least Privilege
Confidence
93% confidence
Finding
The skill advertises credential storage, approval workflows, and external notifications, and the examples explicitly imply access to environment secrets and network-capable channels, but it declares no explicit tool scope or allowed-tools boundary. In a security-oriented skill, undeclared capabilities are especially risky because users may trust it to enforce boundaries while the runtime permissions remain ambiguous and potentially broader than expected.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
## Permission Levels

| Level | Auto-approve | Requires Human |
|-------|--------------|----------------|
| `read` | ✅ Read operations | ❌ |
| `write` | ✅ Read/Write | ❌ |
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
## Permission Levels

| Level | Auto-approve | Requires Human |
|-------|--------------|----------------|
| `read` | ✅ Read operations | ❌ |
| `write` | ✅ Read/Write | ❌ |
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Autonomous Decision Making

Medium
Category
Excessive Agency
Content
## Permission Levels

| Level | Auto-approve | Requires Human |
|-------|--------------|----------------|
| `read` | ✅ Read operations | ❌ |
| `write` | ✅ Read/Write | ❌ |
Confidence
85% confidence
Finding
Skill enables autonomous high-impact decisions without human-in-the-loop verification. Critical operations (destructive commands, financial transactions, data deletion) should require explicit user confirmation.

Sudo/Root Execution

Medium
Category
Privilege Escalation
Content
- Send messages/emails
- Financial transactions
- Delete data
- Modify system config
- Access sensitive credentials
- External API calls (configurable)
Confidence
60% confidence
Finding
Commands invoke sudo or root privileges. Verify this elevated access is necessary and justified.

Missing User Warnings

Medium
Confidence
95% confidence
Finding
The setup example instructs users to export a master password in a shell environment variable without warning that environment variables can persist in shell history, process listings, CI logs, or inherited subprocess environments. For a security-focused tool, showing this as the default workflow may cause users to handle real secrets insecurely.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The documentation demonstrates retrieving a stored credential and states that the value is directly printed for scripting convenience, but it does not warn that secrets may be exposed in terminal scrollback, logs, screenshots, or piped subprocesses. In a credential-management skill, normalized examples like this can encourage unsafe secret handling patterns and lead users to leak live API keys during routine use.

External Transmission

Medium
Category
Data Exfiltration
Content
const apiKey = await guard.getCredential('nano', 'OPENAI_API_KEY');

// 使用 API
const response = await fetch('https://api.openai.com/v1/completions', {
  headers: { 'Authorization': `Bearer ${apiKey}` }
});
```
Confidence
50% confidence
Finding
Data is being sent to an external URL. This could be legitimate telemetry or data exfiltration. Manual review is recommended.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The documentation tells users to store a credential directly on the command line (`agentguard vault store my-agent API_KEY xxx`), which can expose secrets through shell history, process inspection, terminal logs, or recorded transcripts. Because this is setup guidance for credential management software, readers may copy the pattern into real deployments and inadvertently leak API keys during onboarding.

Description-Behavior Mismatch

Medium
Confidence
88% confidence
Finding
The manifest describes AgentGuard as trust middleware focused on credential storage, permission scopes, human approval, and audit trails. This document introduces a broader 'Credit Score System' for agent reputation scoring and ranking, which is a materially different product capability rather than an obvious implementation detail of the stated features.

Context-Inappropriate Capability

Medium
Confidence
94% confidence
Finding
The report example recommends 'suggestedPermissions: ["admin"]' based on a reputation score, which normalizes privilege elevation from behavioral scoring rather than least-privilege review. In a credential and permission-guarding skill, this is dangerous because operators may treat a soft trust metric as sufficient justification for granting broad administrative access.

Missing User Warnings

Medium
Confidence
93% confidence
Finding
The documentation explicitly shows bypassing approval for high-scoring agents and auto-adjusting permissions without a strong warning about integrity and abuse risks. In the context of a security middleware skill, guidance that encourages approval bypass and automated elevation can lead adopters to weaken controls around dangerous operations.

Context-Inappropriate Capability

Medium
Confidence
96% confidence
Finding
The dynamic permissions example automatically increases an agent's permission level as its score rises, including promotion to admin at high scores. This creates an unsafe trust-to-privilege pipeline that can be gamed or miscalculated, turning reputation manipulation or scoring errors into direct privilege escalation.

Missing User Warnings

Medium
Confidence
91% confidence
Finding
The documentation shows approval details, including recipient and subject, being sent to Feishu without any warning that operational data will be disclosed to a third-party messaging platform. In a permission/approval system, these fields can contain sensitive business or personal information, so normal use can unintentionally leak data outside the primary system boundary.

Static analysis

Detected: suspicious.dangerous_exec, suspicious.exposed_secret_literal

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
src/1password.js:25

File appears to expose a hardcoded API secret or token.

Critical
Code
suspicious.exposed_secret_literal
Location
TEST-REPORT.md:12