Back to skill

Security audit

Supabase Vault

Security checks for vulnerabilities and agentic risk

Overview

This skill is a real Supabase-based secrets integration, but it handles very sensitive credentials and secrets with several under-scoped or overstated safeguards that should be reviewed before install.

Install only if you are comfortable giving this skill persistent access to a Supabase service_role key and letting it rewrite OpenClaw secret configuration. Use a dedicated Supabase project, pin and verify dependencies, validate the Supabase URL yourself, rotate the service_role key if exposed, and manually decide what to do with the original ~/.openclaw/secrets.json after migration.

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 (6)

T09 · Insecure Skill Coding Practices

Error
Location
assets/rpc-handler.ts:69
Finding
Service-role credential exposed through child-process arguments<![CDATA[ ## Vulnerability Details **File Location**: `assets/rpc-handler.ts:69-75` **Vulnerability Type**: Sensitive credential exposure through process arguments **Risk Level**: High ### Vulnerable Code ```typescript async function keychainStore(url: string, serviceRoleKey: string): Promise<void> { await execFileAsync("node", [ "-e", `const k=require(${JSON.stringify(KEYCHAIN_JS)});k.store(${JSON.stringify(url)},${JSON.stringify(serviceRoleKey)});`, ]); } ``` ### Technical Analysis The Supabase service-role key and project URL are serialized directly into the argument passed to `node -e`. Although `execFileAsync` avoids shell interpretation, it does not protect argument confidentiality. The resulting command line can be visible to local process-inspection utilities, endpoint monitoring software, audit systems, crash collectors, or other processes with sufficient access. The service-role key is particularly sensitive because it bypasses Supabase Row Level Security. This subprocess is unnecessary for confidential data transport. If CommonJS interoperability requires a child process, the credentials should be supplied over a protected standard-input pipe rather than placed in `argv`. ### Attack Path 1. A user connects the Skill to Supabase through the dashboard. 2. The gateway calls `keychainStore`. 3. A transient `node -e` process starts with the complete service-role key embedded in its command-line argument. 4. A local process monitor, telemetry agent, or sufficiently privileged local process records or reads that argument. 5. The captured key is used to invoke Supabase APIs with service-role privileges. ### Impact Assessment An attacker who captures this credential may obtain broad access to the associated Supabase project. The service-role credential can bypass RLS and may permit reading or modifying data beyond the Vault functions, depending on the project configuration. The Skill recommends a dedicated project, which reduces collat ...[truncated 67 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Never place credentials in command-line arguments. - Pass a JSON payload through the child process's standard input. - Have the child read from file descriptor 0 and immediately clear temporary buffers after parsing. - Alternatively, import the keychain module through a controlled compatibility wrapper without spawning a child process. - Ensure errors and telemetry never include the supplied service-role key. - Document and enforce service-role key rotation after any suspected process-argument exposure. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
scripts/crypto-local.js:46
Finding
Machine-derived fallback encryption lacks secret key material<![CDATA[ ## Vulnerability Details **File Location**: `scripts/crypto-local.js:46-52` **Vulnerability Type**: Predictable encryption key derivation **Risk Level**: High ### Vulnerable Code ```javascript function deriveKey(salt) { const machineId = getMachineId(); const username = os.userInfo().username; const password = `${machineId}:${username}:${APP_SALT}`; return crypto.pbkdf2Sync(password, salt, PBKDF2_ITERATIONS, KEY_LEN, PBKDF2_DIGEST); } ``` The derived key protects credentials stored by the fallback implementation: ```javascript function aesStore(payload) { const json = JSON.stringify(payload); const blob = encrypt(json); fs.mkdirSync(path.dirname(ENC_FILE), { recursive: true }); fs.writeFileSync(ENC_FILE, blob, { mode: 0o600 }); } ``` ### Technical Analysis The fallback key is derived from the machine ID, username, and a hard-coded application string. None of these values are secret: - The machine ID is commonly readable from `/etc/machine-id` or included in system backups and forensic images. - The username is readily discoverable. - `APP_SALT` is embedded in the distributed source code. - The random PBKDF2 salt is stored in the encrypted file header. PBKDF2 increases derivation cost, but it cannot create secrecy when all input material is known. AES-256-GCM correctly provides authenticated encryption, but its effective security depends on the confidentiality of the derived key. The implementation therefore provides machine binding and protection against casual copying to an unrelated machine, not robust encryption against an attacker who obtains the credential file and corresponding machine metadata. ### Attack Path 1. An attacker obtains `~/.openclaw/supabase-vault-config.enc`, such as through a backup leak or filesystem disclosure. 2. The attacker obtains or reconstructs the machine ID and username from the same backup or system image. 3. The attacker reads the public application salt and PBKDF2 parameters from the Skill ...[truncated 537 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Store a randomly generated wrapping key in an OS keychain, TPM, hardware security module, or another protected credential facility. - If no protected store exists, require a user-supplied passphrase with sufficient entropy. - Derive the encryption key from that secret passphrase using an appropriate password-based KDF. - Treat machine ID and username only as optional context or binding data, not as secret key material. - Clearly label the existing fallback as obfuscation or machine binding if backward compatibility requires retaining it. - Provide a migration mechanism that re-encrypts existing credential files with the stronger design. ]]>

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/fetch-secrets.js:73
Finding
Empty secret request retrieves and prints the entire Vault<![CDATA[ ## Vulnerability Details **File Location**: `scripts/fetch-secrets.js:73-112` **Vulnerability Type**: Excessive secret access and bulk disclosure **Risk Level**: High ### Vulnerable Code ```javascript let namesToFetch = requestedIds.map(stripLeadingSlash); // If no args, fetch all secrets if (namesToFetch.length === 0) { const { data, error } = await supabase.rpc("list_secret_names"); if (error) { output({}, { _list: { message: `fetch-secrets: failed to list secrets — ${error.message}` } }); process.exit(0); } namesToFetch = (data || []).map((row) => (typeof row === "string" ? row : row.name)); } // Fetch each secret await Promise.all( namesToFetch.map(async (name) => { const refKey = addLeadingSlash(name); try { const { data, error } = await supabase.rpc("read_secret", { secret_name: name }); if (error) { errors[refKey] = { message: error.message }; } else if (data === null || data === undefined) { errors[refKey] = { message: `Secret "${name}" not found in Vault` }; } else { values[refKey] = String(data); } } catch (err) { errors[refKey] = { message: String(err.message || err) }; } }) ); ``` The results are subsequently returned through standard output: ```javascript clearTimeout(timeoutHandle); output(values, errors); ``` ### Technical Analysis The script is intended to resolve specifically requested OpenClaw SecretRefs. The minimum privilege necessary is therefore access only to the named secrets required by the current request. Instead, invoking the script without arguments lists every secret and then decrypts and prints every value. This fail-open default turns an empty or malformed request into a bulk Vault export. The configured `trustedDirs` restriction may protect the exec provider's script path, but it does not prevent another process running as the same user from directly invoking the script. It also does not mitigate accidental invoca ...[truncated 807 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Reject empty requests instead of treating them as a request for all secrets. - Require at least one explicitly requested SecretRef. - Validate each identifier against a strict naming format and configured allowlist. - Apply a maximum number of secrets per invocation. - Consider replacing multiple per-secret calls with a narrowly scoped server function that accepts only the required names. - Keep bulk export as a separate administrative command requiring explicit confirmation and authorization. - Return a protocol error when no IDs are provided. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/migrate.js:196
Finding
Migration leaves the original plaintext secret vault intact<![CDATA[ ## Vulnerability Details **File Location**: `scripts/migrate.js:196-207` **Vulnerability Type**: Residual plaintext sensitive data **Risk Level**: Medium ### Vulnerable Code ```javascript // Patch openclaw.json head("Updating openclaw.json..."); try { const config = readConfig(); const migratedSet = new Set(migrated.map((k) => `/${k}`)); patchRefsInObject(config, migratedSet); addSupabaseProvider(config); writeConfig(config); ok("openclaw.json updated — SecretRefs now point to Supabase provider"); } catch (e) { err(`Failed to update openclaw.json: ${e.message}`); } ``` No subsequent operation deletes, truncates, encrypts, or otherwise protects `~/.openclaw/secrets.json`. The behavior is acknowledged in `SKILL.md:140-141`: ```markdown Migration moves all keys from `secrets.json` to Supabase Vault and updates all SecretRefs in `openclaw.json` from `file` → `exec/supabase`. The local `secrets.json` is left in place as a safety backup. ``` This conflicts with the threat-model claim in `references/architecture.md:34-36` that plaintext-on-disk exposure is eliminated. ### Technical Analysis Migration copies secrets to Supabase and rewrites configuration references, but the original plaintext source remains on disk indefinitely. Consequently, migration does not remove the original disclosure path. Keeping a safety backup can be a legitimate operational choice, but retaining it in plaintext contradicts the stated security objective and should require explicit informed consent. A secure migration should verify remote writes and then offer deletion or encrypted archival of the original file. ### Attack Path 1. A user completes migration to Supabase Vault. 2. The configuration starts referencing the Supabase exec provider. 3. The original `~/.openclaw/secrets.json` remains unchanged. 4. An attacker who later gains read access to that file obtains all migrated values directly. 5. The attacker does not need to compromise Supabase Vault or ...[truncated 318 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - After all remote writes are verified, explicitly ask whether the user wants to remove the plaintext source. - Create a permission-preserving backup before configuration changes, but encrypt that backup with an independently protected key. - Use atomic configuration writes and retain rollback metadata without retaining plaintext secret values. - If deletion is selected, remove the source file and warn that secure erasure cannot always be guaranteed on copy-on-write or solid-state storage. - If the user keeps the file, clearly state that local plaintext disclosure remains possible. - Correct the architecture and UI claims so they accurately describe the retained backup. ]]>

T08 · Insecure Dependencies

Warning
Location
SKILL.md:27
Finding
Secret-handling dependency is installed without version or integrity pinning<![CDATA[ ## Vulnerability Details **File Location**: `SKILL.md:27-31` **Vulnerability Type**: Unpinned third-party dependency **Risk Level**: Medium ### Vulnerable Code ```bash npm install --prefix ~/.openclaw/skills/supabase-vault @supabase/supabase-js ``` ### Technical Analysis The installation instructions request the latest version of `@supabase/supabase-js` available from the configured npm registry. The project does not include a lockfile, exact version constraint, or integrity metadata. This package runs inside a highly sensitive trust boundary. It receives the Supabase service-role credential, sends Vault RPC requests, and processes decrypted secret values. An unexpectedly changed, compromised, or maliciously resolved package version would therefore have access to critical credentials and secrets. The code also falls back to resolving a globally or parent-installed copy: ```javascript ({ createClient } = require("@supabase/supabase-js")); ``` That fallback further reduces assurance about which package instance is executed. ### Attack Path 1. A user follows the documented installation command. 2. npm resolves the current package version from the configured registry rather than a reviewed exact release. 3. A compromised release, registry configuration, or dependency chain installs altered code. 4. The gateway or fetch script loads that code. 5. The dependency gains access to the service-role key and secret RPC responses. 6. The altered package can disclose or modify those values using its normal network privileges. ### Impact Assessment A compromised dependency could access all Vault secrets and the service-role credential, modify RPC behavior, or send data to an unauthorized destination. The scope is the OpenClaw user's secret store and potentially the broader Supabase project. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions - Pin `@supabase/supabase-js` to an audited exact version. - Include and distribute a lockfile with integrity hashes. - Use reproducible installation such as `npm ci`. - Avoid falling back to an uncontrolled globally or parent-installed package. - Verify the resolved module path before loading it. - Establish a controlled dependency-update process that includes security review and testing. - Consider vendoring or bundling the reviewed client code if the deployment model permits it. ]]>

T09 · Insecure Skill Coding Practices

Error
Location
assets/rpc-handler.ts:143
Finding
Unrestricted Supabase endpoint can receive privileged credentials and migrated secrets<![CDATA[ ## Vulnerability Details **File Location**: `assets/rpc-handler.ts:143-164` **Vulnerability Type**: Unvalidated sensitive-data destination **Risk Level**: High ### Vulnerable Code ```typescript "supabase-vault.connect": async ({ params: p, respond }) => { try { const { url, serviceRoleKey } = p as { url?: string; serviceRoleKey?: string }; if (!url?.trim() || !serviceRoleKey?.trim()) { respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "url and serviceRoleKey required")); return; } // Test connection const supabase = makeClient(url.trim(), serviceRoleKey.trim()); const { error } = await supabase.rpc("list_secret_names"); if (error) { respond(false, undefined, errorShape( ErrorCodes.UNAVAILABLE, `Connection test failed: ${error.message}. Make sure you ran setup.sql in your Supabase project.` )); return; } // Store credentials await keychainStore(url.trim(), serviceRoleKey.trim()); ``` The supplied destination is passed directly to the client: ```typescript function makeClient(url: string, serviceRoleKey: string) { const { createClient } = requireSupabase(); return createClient(url, serviceRoleKey, { auth: { persistSession: false, autoRefreshToken: false }, }); } ``` ### Technical Analysis The gateway validates only that the URL and key are non-empty. It does not enforce HTTPS, validate the origin against an expected Supabase host or approved self-hosted deployment, or restrict loopback and link-local addresses. Because the service-role key is supplied to the client for the connection test, an attacker-controlled or mistakenly entered endpoint can receive the credential. If the endpoint emulates the expected RPC response, it can be persisted as the Vault destination. A later migration will then send all local secret values to that endpoint. Network transmission is required for the Skill's declared functionality, but unrestricted des ...[truncated 1142 chars]
Remediation
<![CDATA[ ## Remediation Suggestions - Parse the supplied value with `URL` and reject malformed URLs. - Require HTTPS for remote deployments. - Permit `*.supabase.co` only after strict hostname-boundary validation, or maintain an explicit allowlist for approved self-hosted origins. - Reject embedded credentials, unexpected ports, loopback, link-local, and private-network destinations unless the user explicitly enables a documented self-hosted mode. - Display the exact normalized destination and require confirmation before storing credentials or migrating secrets. - Bind migration to the previously verified origin and repeat origin validation immediately before migration. - Ensure gateway authorization prevents untrusted dashboard clients from invoking connect or migration RPC methods. ]]>
Vulnerability Patterns
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (58)

Ae1

High
Category
analysis-evasion
Content
Copy `assets/rpc-handler.ts` to `src/gateway/server-methods/supabase-vault.ts` in the OpenClaw source, then register it in the server-methods index:
Confidence
100% confidence
Finding
Referenced artifact was not completely inspected

Credential Access

High
Category
Privilege Escalation
Content
```
Gateway starts
  → exec provider triggers fetch-secrets.js
      → keychain.js retrieves SUPABASE_URL + SERVICE_ROLE_KEY
          (macOS: Keychain Access / Linux: GNOME Keyring / fallback: AES-256-GCM file)
      → @supabase/supabase-js createClient(url, key)
      → supabase.rpc('read_secret', { secret_name }) for each requested key
Confidence
86% confidence
Finding
The documented design requires retrieving the Supabase `SERVICE_ROLE_KEY` at runtime to read secrets. A service-role credential is highly privileged and bypasses RLS; if the host, exec provider, or local credential store is compromised, an attacker can access or manipulate all vault secrets for the project.

Credential Access

High
Category
Privilege Escalation
Content
const execFileAsync = promisify(execFile);

const SKILL_DIR    = path.join(os.homedir(), ".openclaw", "skills", "supabase-vault");
const KEYCHAIN_JS  = path.join(SKILL_DIR, "scripts", "keychain.js");
const MIGRATE_JS   = path.join(SKILL_DIR, "scripts", "migrate.js");
const SECRETS_FILE = path.join(os.homedir(), ".openclaw", "secrets.json");
const CONFIG_FILE  = path.join(os.homedir(), ".openclaw", "openclaw.json");
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
const execFileAsync = promisify(execFile);

const SKILL_DIR    = path.join(os.homedir(), ".openclaw", "skills", "supabase-vault");
const KEYCHAIN_JS  = path.join(SKILL_DIR, "scripts", "keychain.js");
const MIGRATE_JS   = path.join(SKILL_DIR, "scripts", "migrate.js");
const SECRETS_FILE = path.join(os.homedir(), ".openclaw", "secrets.json");
const CONFIG_FILE  = path.join(os.homedir(), ".openclaw", "openclaw.json");
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
const execFileAsync = promisify(execFile);

const SKILL_DIR    = path.join(os.homedir(), ".openclaw", "skills", "supabase-vault");
const KEYCHAIN_JS  = path.join(SKILL_DIR, "scripts", "keychain.js");
const MIGRATE_JS   = path.join(SKILL_DIR, "scripts", "migrate.js");
const SECRETS_FILE = path.join(os.homedir(), ".openclaw", "secrets.json");
const CONFIG_FILE  = path.join(os.homedir(), ".openclaw", "openclaw.json");
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
const execFileAsync = promisify(execFile);

const SKILL_DIR    = path.join(os.homedir(), ".openclaw", "skills", "supabase-vault");
const KEYCHAIN_JS  = path.join(SKILL_DIR, "scripts", "keychain.js");
const MIGRATE_JS   = path.join(SKILL_DIR, "scripts", "migrate.js");
const SECRETS_FILE = path.join(os.homedir(), ".openclaw", "secrets.json");
const CONFIG_FILE  = path.join(os.homedir(), ".openclaw", "openclaw.json");
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
const execFileAsync = promisify(execFile);

const SKILL_DIR    = path.join(os.homedir(), ".openclaw", "skills", "supabase-vault");
const KEYCHAIN_JS  = path.join(SKILL_DIR, "scripts", "keychain.js");
const MIGRATE_JS   = path.join(SKILL_DIR, "scripts", "migrate.js");
const SECRETS_FILE = path.join(os.homedir(), ".openclaw", "secrets.json");
const CONFIG_FILE  = path.join(os.homedir(), ".openclaw", "openclaw.json");
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
return JSON.parse(stdout.trim());
}

async function keychainRetrieve(): Promise<{ url: string; serviceRoleKey: string }> {
  const { stdout } = await execFileAsync("node", [
    "-e",
    `const k=require(${JSON.stringify(KEYCHAIN_JS)});try{console.log(JSON.stringify(k.retrieve()));}catch(e){console.log(JSON.stringify({error:e.message}));}`,
Confidence
72% confidence
Finding
This handler retrieves high-privilege Supabase credentials into process memory and over a child-process stdout boundary, which increases the attack surface for secrets exposure if the helper script, process environment, or error handling is compromised. In this skill context that access is expected, but using a service-role key makes the consequences of accidental exposure materially higher.

Credential Access

High
Category
Privilege Escalation
Content
return result;
}

async function keychainStore(url: string, serviceRoleKey: string): Promise<void> {
  await execFileAsync("node", [
    "-e",
    `const k=require(${JSON.stringify(KEYCHAIN_JS)});k.store(${JSON.stringify(url)},${JSON.stringify(serviceRoleKey)});`,
Confidence
76% confidence
Finding
The code sends the Supabase URL and service-role key as arguments embedded in a 'node -e' command string to a child process. Even though 'execFile' avoids shell injection, transporting secrets to another process can expose them to process inspection, debugging tools, crash dumps, or less controlled helper code, which is sensitive given the service-role key's broad privileges.

Credential Access

High
Category
Privilege Escalation
Content
let keyCount = 0;

        try {
          const creds = await keychainRetrieve();
          urlMasked = maskUrl(creds.url);

          // Test connection by listing secrets
Confidence
71% confidence
Finding
The status endpoint retrieves stored backend credentials and actively tests them against Supabase, even though it only returns masked metadata. That broadens the set of code paths that access sensitive service-role credentials, increasing exposure if the RPC surface is reachable by less-trusted callers or if child-process retrieval is compromised.

Credential Access

High
Category
Privilege Escalation
Content
}

        // Store credentials
        await keychainStore(url.trim(), serviceRoleKey.trim());

        // Add exec provider to config
        const config = readConfig();
Confidence
83% confidence
Finding
This line stores a Supabase service-role key for later automated use, giving the local application persistent access to a highly privileged backend credential. In a secrets-management skill this is functionally necessary, but if the keychain helper or host is compromised, an attacker gains broad ability to read, write, and delete stored secrets remotely.

Credential Access

High
Category
Privilege Escalation
Content
"supabase-vault.list": async ({ respond }) => {
      try {
        const creds = await keychainRetrieve();
        const supabase = makeClient(creds.url, creds.serviceRoleKey);
        const { data, error } = await supabase.rpc("list_secret_names");
        if (error) throw new Error(error.message);
Confidence
78% confidence
Finding
The list endpoint retrieves stored service-role credentials and uses them to enumerate secrets from the remote vault. While expected for functionality, this means any unauthorized access to this RPC could disclose secret inventory and confirms live access to a privileged secrets backend, which is especially sensitive in a vault-management context.

Credential Access

High
Category
Privilege Escalation
Content
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "name and value required"));
          return;
        }
        const creds = await keychainRetrieve();
        const supabase = makeClient(creds.url, creds.serviceRoleKey);
        const { data, error } = await supabase.rpc("insert_secret", {
          name: name.trim(),
Confidence
80% confidence
Finding
The write endpoint retrieves stored service-role credentials and uses them to insert secrets into the remote vault. In context this is intended behavior, but compromise of this RPC or of the stored credential path would let an attacker alter the application's secret store, potentially planting malicious API keys, tokens, or configuration values.

Credential Access

High
Category
Privilege Escalation
Content
respond(false, undefined, errorShape(ErrorCodes.INVALID_REQUEST, "name required"));
          return;
        }
        const creds = await keychainRetrieve();
        const supabase = makeClient(creds.url, creds.serviceRoleKey);
        const { error } = await supabase.rpc("delete_secret", { secret_name: name.trim() });
        if (error) throw new Error(error.message);
Confidence
80% confidence
Finding
The delete endpoint retrieves privileged backend credentials and can remove secrets from the vault. In a secrets-management skill that is expected, but if invoked by an unauthorized party it could cause denial of service, break integrations, or force secret rotation across dependent systems.

Credential Access

High
Category
Privilege Escalation
Content
│ OPENAI   │  ◄────────┤
                                    │ (encr.)  │           │ ┌────────────────┐
                                    └──────────┘           └►│ macOS Keychain │
                                                             │ GNOME Keyring  │
                                                             │ AES-256-GCM    │
                                                             │ (machine key)  │
                                                             └────────────────┘
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
│ OPENAI   │  ◄────────┤
                                    │ (encr.)  │           │ ┌────────────────┐
                                    └──────────┘           └►│ macOS Keychain │
                                                             │ GNOME Keyring  │
                                                             │ AES-256-GCM    │
                                                             │ (machine key)  │
                                                             └────────────────┘
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
/**
 * keychain.js — Platform-aware bootstrap credential storage
 *
 * Priority order:
 *   1. macOS Keychain    (security CLI)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
/**
 * keychain.js — Platform-aware bootstrap credential storage
 *
 * Priority order:
 *   1. macOS Keychain    (security CLI)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
/**
 * keychain.js — Platform-aware bootstrap credential storage
 *
 * Priority order:
 *   1. macOS Keychain    (security CLI)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
/**
 * keychain.js — Platform-aware bootstrap credential storage
 *
 * Priority order:
 *   1. macOS Keychain    (security CLI)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
/**
 * keychain.js — Platform-aware bootstrap credential storage
 *
 * Priority order:
 *   1. macOS Keychain    (security CLI)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
/**
 * keychain.js — Platform-aware bootstrap credential storage
 *
 * Priority order:
 *   1. macOS Keychain    (security CLI)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
/**
 * keychain.js — Platform-aware bootstrap credential storage
 *
 * Priority order:
 *   1. macOS Keychain    (security CLI)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
/**
 * keychain.js — Platform-aware bootstrap credential storage
 *
 * Priority order:
 *   1. macOS Keychain    (security CLI)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Credential Access

High
Category
Privilege Escalation
Content
/**
 * keychain.js — Platform-aware bootstrap credential storage
 *
 * Priority order:
 *   1. macOS Keychain    (security CLI)
Confidence
70% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Static analysis

Detected: suspicious.dangerous_exec

Shell command execution detected (child_process).

Critical
Code
suspicious.dangerous_exec
Location
scripts/keychain.js:33