Back to skill

Security audit

LinkedCareer

Security checks for vulnerabilities and agentic risk

Overview

LinkedCareer is a coherent local career-profile and resume tool, with privacy and supply-chain hardening issues users should understand before installing.

Before installing, be comfortable storing resume, contact, education, and job-history data locally in plaintext under the LinkedCareer user-data directory, with a duplicate Markdown copy. Use it on a private device, protect or delete those files when needed, and be aware that installation downloads npm dependencies without a committed lockfile.

Vulnerability Patterns
  • 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
  • Remote Payload Retrieval and ExecutionFetches external code whose behavior can change after review
Findings (3)

T09 · Insecure Skill Coding Practices

Warning
Location
src/core/memory.js:9
Finding

Sensitive Career and Identity Data Is Stored Without Explicit Restrictive Permissions

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
templates/resume_professional.html:99
Finding

Unescaped User-Controlled Achievement Content in the HTML Resume Template

Content
View full analysis
{{{this}}} {{/each}} ``` ### Technical Analysis The triple-brace expression `{{{this}}}` performs unescaped interpolation in Handlebars-style template engines. Achievement entries originate from onboarding answers, career records, or imported resume content and must therefore be treated as untrusted input. If this template is connected to an HTML resume generator, attacker-controlled achievement content can be inserted directly into the generated HTML. A malicious value could contain HTML elements, event-handler attributes, remote resource references, or other active markup. For example, an imported achievement could contain markup similar to: ```html ``` The current CLI path shown in `src/index.js` generates Markdown or DOCX and does not directly render this HTML template. Consequently, the vulnerable sink is currently dormant in the audited command path. It becomes exploitable if the template is rendered by another platform integration or a future HTML/PDF export implementation. ### Attack Path 1. An attacker creates resume content containing malicious HTML in an achievement field. 2. A victim imports that resume, or otherwise stores the attacker-controlled achievement. 3. An HTML export or platform integration renders `resume_professional.html` with the stored career data. 4. Triple-brace interpolation inserts the achievement without escaping. 5. The generated HTML is opened in a browser or processed by an HTML-capable document converter. 6. Depending on the renderer's security model, the payload may execute script, load a remote tracking resource, alter displayed content, or access ...[truncated 748 chars]
Remediation
View remediation
{{this}} {{/each}} ``` 2. Ensure every user-controlled field is escaped according to its output context, including names, companies, positions, descriptions, contact details, skills, and education fields. 3. If limited formatting is required, sanitize content with a strict allowlist rather than disabling escaping. Exclude: - `script`, `iframe`, `object`, and `embed` elements - Event-handler attributes such as `onerror` and `onclick` - `javascript:` and other dangerous URL schemes - Remote images, stylesheets, and fonts unless explicitly authorized 4. Configure HTML-to-PDF or browser renderers to disable JavaScript and remote network requests. 5. Add security tests containing HTML tags, event handlers, dangerous URLs, and remote resource references, and verify that they appear only as inert text. ]]>

T08 · Insecure Dependencies

Note
Location
SKILL.md:11
Finding

Production Dependency Installation Is Not Locked to a Reproducible Dependency Graph

Content
View full analysis
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Rogue AgentSelf-Modification, Session Persistence
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
Findings (38)

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

The declared description presents a narrow career/resume function, but the implementation reportedly performs additional actions such as writing files, cover-letter generation, JD matching, and Word export without corresponding disclosure or permissions. This mismatch is dangerous because users and reviewers may approve the skill under false assumptions, while the runtime behavior can create or overwrite local files and process more data than expected.

Content

No source excerpt is available for this finding.

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
81% confidence
Finding

The skill declares runtime execution and detected access to environment capabilities but does not define any explicit tool scope or permissions. In an agent ecosystem, missing scope declarations weaken reviewability and can allow the skill to access sensitive environment data beyond what users would reasonably expect from a resume tool.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

The design explicitly collects and stores highly sensitive personal and career data, including contact details, education, employment history, and uploaded resumes, but does not mention local encryption, access controls, retention limits, or user-facing warnings about device compromise and file exposure. Although local-only storage reduces third-party exfiltration risk, plaintext storage under a predictable path can still expose users if the host is shared, malware-infected, backed up insecurely, or synced automatically.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
82% confidence
Finding

The file title and the entire skill design are presented in Chinese, and there is no natural-language indication that users may choose another language or locale. Under the policy criteria, forcing a specific language without opt-in can be a locale-policy violation unless it is explicitly justified as region-specific.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

The skill explicitly solicits sensitive personal data including name, phone number, email, city, age, gender, and even an old resume, but provides no notice about storage, retention, sharing, or safe handling. In a career-management context this increases privacy risk because users are encouraged to submit a large amount of personally identifiable and potentially employment-sensitive information without informed consent or minimization.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

All user-facing prompts and examples in the skill are written in Chinese, and the extraction logic is also tailored to Chinese-language patterns, with no indication that the user can choose another language. This can violate language/locale policy when a skill imposes a specific language without opt-in or documented regional scope.

Content

No source excerpt is available for this finding.

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 72)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 121)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 128)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 133)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 134)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 142)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 161)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 163)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 164)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 254)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 259)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 260)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 263)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Session Persistence

Medium
Category
Rogue Agent
Confidence
75% confidence
Finding

Skill establishes unauthorized persistence across sessions via cron jobs, startup scripts, or state files. Session persistence allows an attacker to maintain access beyond the current interaction.

Content

Scanner excerpt · src/core/interview.js (reported line 264)May include surrounding context.

js
// 是否正在进行深度梳理
    this.isDeepDiving = false
    // 深度梳理的经历列表(优先最近5年)
    this.deepDiveExpList = []
    // 是否已经完成最近5年的梳理,待确认是否继续更早的经历
    this.needConfirmMoreDive = false
  }

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The comment at L119 states that older experiences will be loaded for continued deep-dive questioning, but the code again filters on exp.endTime, which is not the field populated for work dates elsewhere in the file. This contradicts the documented behavior because the branch intended to select earlier experiences is not operating on the stored interview data shape.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
97% confidence
Finding

The inline comment at L252 says the code will prioritize experiences from the last 5 years, but the actual filter reads exp.endTime even though experience dates are stored earlier under the field name time (L234 and similar). Because endTime is never populated in this file, the filter does not implement the documented intent and may incorrectly exclude recent entries before falling back to all experiences.

Content

No source excerpt is available for this finding.

Natural-Language Policy Violations

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The file contains user-facing comments, console output, and formatted results entirely in Chinese, including progress logs and final recommendation text. Under the policy, forcing a specific language without opt-in or a documented regional justification is a natural-language policy violation.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The save flow persists structured career data, which can include personal identifiers like name, phone number, email, education, and work history, to files under the user's home directory. This code performs the writes silently and does not include a confirmation prompt, logging, or inline disclosure about the storage behavior.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
93% confidence
Finding

This method converts potentially sensitive career information into a markdown record and writes it to career_records.md. The operation affects user data on disk, but the code provides no confirmation, visible notice, or explanatory comment indicating that a second human-readable copy will be created.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.