Back to skill

Security audit

Keyapi Linkedin

Security checks for vulnerabilities and agentic risk

Overview

The skill is coherent for LinkedIn data lookup, but it needs Review because it stores an API token in plaintext shell profile files and enables contact/profile data collection without strong privacy guardrails.

Install only if you are comfortable with a local shell profile being modified to store a KeyAPI bearer token in plaintext. Prefer setting KEYAPI_TOKEN only for the current session or using a separate secret manager, avoid the --token command form, and use the LinkedIn contact/profile workflows only for authorized, necessary, and compliant business purposes.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
  • Embedded Malicious CodeShips malicious scripts inside the skill and executes them locally
Findings (1)

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/configure-keyapi-auth.mjs:187
Finding

Bearer Token Is Exposed During Entry and Persisted in Plaintext

Content
View full analysis

Vulnerability Details

File Location: scripts/configure-keyapi-auth.mjs:187-211, 220-226
Vulnerability Type: Plaintext credential handling and insecure secret input
Risk Level: Medium

Vulnerable Code

js
async function collectCredentials(args) {
  const token = args.token ? requireRealValue("KEYAPI_TOKEN", args.token) : undefined;

  if (token) {
    return { token };
  }

  const rl = createInterface({ input, output });

  try {
    output.write("KeyAPI setup will save KEYAPI_TOKEN into your shell environment variables.\n");
    const enteredToken = await rl.question("Paste KEYAPI_TOKEN: ");

    return {
      token: requireRealValue("KEYAPI_TOKEN", enteredToken)
    };
  } finally {
    rl.close();
  }
}

function writeProfile(profilePath, credentials) {
  ensureParentDir(profilePath);
  const profileKind = detectProfileKind(profilePath);
  const existing = fs.existsSync(profilePath) ? fs.readFileSync(profilePath, "utf8") : "";
  const cleaned = stripManagedBlock(existing);
  const block = buildManagedBlock(credentials, profileKind);
  const next = cleaned ? `${cleaned}\n\n${block}` : block;
  fs.writeFileSync(profilePath, next);
  return profileKind;
}

The token is embedded into the generated profile block:

js
function buildManagedBlock(values, profileKind) {
  if (profileKind === "powershell") {
    return [
      managedBlockStart,
      `$env:KEYAPI_TOKEN = ${powershellQuote(values.token)}`,
      managedBlockEnd,
      ""
    ].join("\n");
  }

  return [
    managedBlockStart,
    `export KEYAPI_TOKEN=${shellQuote(values.token)}`,
    managedBlockEnd,
    ""
  ].join("\n");
}

The documentation also offers command-line token entry at references/setup-and-auth.md:39-43:

bash
node scripts/configure-keyapi-auth.mjs --token "your_keyapi_token"

Technical Analysis

The interactive setup reads KEYAPI_TOKEN through a normal readline prompt. Unlike a password-specific terminal input mechanism, this does not ...[truncated 2150 chars]

Remediation
View remediation

Remediation Suggestions

  1. Replace ordinary readline token collection with a secret-input implementation that disables terminal echo and reliably restores terminal settings on success, interruption, and error.
  2. Remove the --token option or mark it unsafe and deprecated. Prefer protected standard input, an OS credential manager, or another secret channel that does not place credentials in process arguments.
  3. Store the token in the platform credential store where available, such as Windows Credential Manager, macOS Keychain, or a Linux Secret Service provider.
  4. If file-based storage is necessary, use a dedicated credential file rather than a general shell profile:
    • Create it atomically with mode 0600 on POSIX systems.
    • Verify that it is owned by the current user.
    • Reject group- or world-readable permissions.
    • Prevent symbolic-link and unsafe replacement attacks.
  5. If shell-profile persistence remains supported, inspect ownership and permissions before reading or writing, preserve secure permissions, and warn the user explicitly that the token will be stored in plaintext.
  6. Remove the command-line token example from references/setup-and-auth.md and document the protected input mechanism instead.
  7. Advise affected users to revoke and rotate tokens that may already have appeared in shell history, terminal recordings, or broadly accessible profile files.
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (26)

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 25)May include surrounding context.

md
2. Check auth with `node scripts/configure-keyapi-auth.mjs --status` when script execution is available and setup state is unknown; treat `authStatus: "availabl

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 26)May include surrounding context.

md
2. Check auth with `node scripts/configure-keyapi-auth.mjs --status` when script execution is available and setup state is unknown; treat `authStatus: "availabl

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 88)May include surrounding context.

md
2. Check auth with `node scripts/configure-keyapi-auth.mjs --status` when script execution is available and setup state is unknown; treat `authStatus: "availabl

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 89)May include surrounding context.

md
2. Check auth with `node scripts/configure-keyapi-auth.mjs --status` when script execution is available and setup state is unknown; treat `authStatus: "availabl

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 98)May include surrounding context.

md
2. Check auth with `node scripts/configure-keyapi-auth.mjs --status` when script execution is available and setup state is unknown; treat `authStatus: "availabl

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 32)May include surrounding context.

md
9. Resolve current docs with `node scripts/search-keyapi-docs.mjs --query "<semantic entity action>" --resolve` when the helper script is available; otherwise o

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 99)May include surrounding context.

md
9. Resolve current docs with `node scripts/search-keyapi-docs.mjs --query "<semantic entity action>" --resolve` when the helper script is available; otherwise o

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 117)May include surrounding context.

md
9. Resolve current docs with `node scripts/search-keyapi-docs.mjs --query "<semantic entity action>" --resolve` when the helper script is available; otherwise o

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 35)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 100)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 102)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 123)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 129)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 135)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 141)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 147)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 153)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 159)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 165)May include surrounding context.

md
12. Prefer `node scripts/keyapi-api.mjs` for live REST calls when script execution is available. Use the host's HTTP client only when scripts are unavailable or

Ae1

High
Category
analysis-evasion
Confidence
100% confidence
Finding

Referenced artifact was not completely inspected

Content

Scanner excerpt · SKILL.md (reported line 102)May include surrounding context.

md
a different current working directory, resolve `scripts/...` relative to this `SKILL.md`. For large JSON bodies, especially base64 image payloads, prefer `--bo

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The skill explicitly routes users toward retrieving employee lists and enriching selected people with user profile data, but it provides no privacy guardrails, lawful-use constraints, or user-facing warning about handling personal data. In a LinkedIn data collection context, this can normalize bulk people mapping and profile enrichment in ways that facilitate unauthorized profiling, targeting, or misuse of personal information.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The rule file explicitly routes the agent to retrieve LinkedIn contact information and other profile/activity data without any privacy guardrails, consent checks, purpose limitation, or data-minimization guidance. In a people-intelligence skill, this can enable unnecessary collection of sensitive personal data for outreach, profiling, or surveillance-like use, especially when combined with other enrichment endpoints.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
92% confidence
Finding

The scenario guidance explicitly routes users toward retrieving LinkedIn contact information and performing live API calls, but it does not require any privacy, consent, or sensitive-data handling checks before collection. In a skill focused on people intelligence and profile enrichment, that omission can normalize unnecessary harvesting of personal data and increase the risk of privacy violations or misuse of scraped contact details.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The script prompts for KEYAPI_TOKEN using readline.question on standard input, which echoes typed characters to the terminal. This can expose the secret to shoulder surfing, screen recording, terminal sharing sessions, or shell/session logging. In an auth configuration script, that makes accidental credential disclosure a real risk.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script writes a bearer token directly into the user's shell profile file, creating a persistent plaintext credential without an explicit confirmation step. If the user did not expect profile modification, this increases the chance of storing secrets in files that may be backed up, synced, inspected by other local users, or later committed or disclosed accidentally. In this skill context, handling API tokens is expected, but silently persisting them in startup files still raises the exposure surface.

Content

No source excerpt is available for this finding.

Static analysis

Detected: suspicious.env_credential_access, suspicious.secret_argv_exposure

Environment variable access combined with network send.

Critical
Code
suspicious.env_credential_access
Location
scripts/keyapi-api.mjs:127

Instructions pass high-value credentials through process argv.

Critical
Code
suspicious.secret_argv_exposure
Location
references/setup-and-auth.md:42