Back to skill

Security audit

Linkedin AI Post Builder and Publisher

Security checks for vulnerabilities and agentic risk

Overview

This LinkedIn skill is mostly purpose-aligned, but it sends unpublished content and an undocumented agent memory file to Gemini and prints LinkedIn tokens in plaintext.

Review this skill before installing. Use it only with non-sensitive drafts unless you are comfortable sending them to Gemini, run preview with --no-feedback when you want local-only preview behavior, avoid sharing terminal output from token generation, and rotate any LinkedIn token that was printed or logged.

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

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/linkedin_auth.py:22
Finding

Predictable OAuth State Does Not Protect Authorization Requests

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/linkedin_auth.py:78
Finding

LinkedIn Access Tokens Are Printed in Plaintext

Content
View full analysis
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Warning
Location
scripts/linkedin.py:253
Finding

Preview Mode Transmits Draft Content to Gemini by Default

Content
View full analysis
Remediation
View remediation

T05 · Unauthorized Access and Privilege Escalation

Error
Location
scripts/generate_draft.py:13
Finding

Undocumented Agent Memory File Is Read and Sent to Gemini

Content
View full analysis
Remediation
View remediation

T08 · Insecure Dependencies

Note
Location
scripts/linkedin.py:1
Finding

Runtime Dependencies Are Not Version-Pinned

Content
View full analysis
=3.12" # dependencies = [ # "requests", # "python-dotenv", # "rich", # ] # /// ``` Other scripts use similarly unpinned dependency declarations, including `requests`, `python-dotenv`, `tabulate`, and `rich`. ### Technical Analysis The inline script metadata specifies package names but no exact versions, lockfile, or integrity hashes. The documented `uv run` workflow may therefore resolve and download package releases that differ from those reviewed during the audit. This is not evidence that the named packages are malicious. The risk arises because the effective executable dependency set is mutable. A compromised upstream release, malicious package takeover, or incompatible future update could introduce code that runs during installation or import. ### Attack Path 1. A user invokes one of the scripts through the documented `uv run` workflow. 2. The dependency resolver obtains currently available versions rather than a reviewed, immutable set. 3. An upstream package or release has been compromised, replaced, or changed incompatibly. 4. The package is installed into the execution environment. 5. Malicious or unsafe package code executes during installation or when imported by the Skill. ### Impact Assessment A compromised Python dependency executes with the privileges of the user running the Skill. It may access environment variables containing `LINKEDIN_ACCESS_TOKEN`, `LINKEDIN_CLIENT_SECRET`, and `GEMINI_API_KEY`, read files available to that user, alter output, or perform network operations. The finding is rated Low because the audit found no evidence that the listed package names ...[truncated 125 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Taint TrackingDirect Taint Flow, Variable-Mediated Taint Flow, Credential Exfiltration Chain
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (49)

Tainted flow: 'data' from os.getenv (line 18, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/exchange_token.py (reported line 26)May include surrounding context.

python
"redirect_uri": REDIRECT_URI,
    }
    headers = {"Content-Type": "application/x-www-form-urlencoded"}
    response = requests.post(url, data=data, headers=headers)
    response.raise_for_status()
    return response.json()

Tainted flow: 'params' from os.getenv (line 48, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/generate_draft.py (reported line 58)May include surrounding context.

python
with console.status("[bold green]Generating draft post..."):
        try:
            response = requests.post(API_URL, params=params, headers=headers, json=payload)
            response.raise_for_status()
            result = response.json()
            draft_content = result['candidates'][0]['content']['parts'][0]['text']

Tainted flow: 'params' from os.getenv (line 63, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/linkedin.py (reported line 89)May include surrounding context.

python
with console.status("[bold green]Analyzing post against top-performers..."):
        try:
            response = requests.post(GEMINI_API_URL, params=params, headers=headers, json=payload)
            response.raise_for_status()
            result = response.json()

Tainted flow: 'url' from os.getenv (line 32, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/linkedin_auth.py (reported line 51)May include surrounding context.

python
"Content-Type": "application/x-www-form-urlencoded"
    }

    response = requests.post(url, data=data, headers=headers)
    response.raise_for_status()
    return response.json()

Tainted flow: 'params' from os.getenv (line 46, credential/environment) → requests.post (network output)

Critical
Category
Data Flow
Confidence
90% confidence
Finding

Credentials or environment variables flow to a network sink. This is a high-confidence indicator of credential exfiltration.

Content

Scanner excerpt · scripts/linkedin_feedback.py (reported line 56)May include surrounding context.

python
with console.status("[bold green]Analyzing post against top-performers..."):
        try:
            response = requests.post(API_URL, params=params, headers=headers, json=payload)
            response.raise_for_status()
            result = response.json()

Tp4

High
Category
MCP Tool Poisoning
Confidence
96% confidence
Finding

Operating as a local CLI analysis tool with undeclared external generative AI usage is materially different from a straightforward LinkedIn integration. This can result in drafts or business content being transmitted to third-party AI services without clear user awareness, creating confidentiality and compliance concerns.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

Operating as a local CLI analysis tool with undeclared external generative AI usage is materially different from a straightforward LinkedIn integration. This can result in drafts or business content being transmitted to third-party AI services without clear user awareness, creating confidentiality and compliance concerns.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Operating as a local CLI analysis tool with undeclared external generative AI usage is materially different from a straightforward LinkedIn integration. This can result in drafts or business content being transmitted to third-party AI services without clear user awareness, creating confidentiality and compliance concerns.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
94% confidence
Finding

Operating as a local CLI analysis tool with undeclared external generative AI usage is materially different from a straightforward LinkedIn integration. This can result in drafts or business content being transmitted to third-party AI services without clear user awareness, creating confidentiality and compliance concerns.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
91% confidence
Finding

Operating as a local CLI analysis tool with undeclared external generative AI usage is materially different from a straightforward LinkedIn integration. This can result in drafts or business content being transmitted to third-party AI services without clear user awareness, creating confidentiality and compliance concerns.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
97% confidence
Finding

Operating as a local CLI analysis tool with undeclared external generative AI usage is materially different from a straightforward LinkedIn integration. This can result in drafts or business content being transmitted to third-party AI services without clear user awareness, creating confidentiality and compliance concerns.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

Operating as a local CLI analysis tool with undeclared external generative AI usage is materially different from a straightforward LinkedIn integration. This can result in drafts or business content being transmitted to third-party AI services without clear user awareness, creating confidentiality and compliance concerns.

Content

No source excerpt is available for this finding.

Credential Access

High
Category
Privilege Escalation
Confidence
87% confidence
Finding

The skill instructs users to generate and handle OAuth access tokens and to export client credentials in their shell environment. Even if intended for legitimate setup, this increases the risk of token leakage through shell history, process inspection, logs, or accidental reuse in broader agent contexts.

Content

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

md
## Setup & Authentication

1.  **Create an App**: Go to [LinkedIn Developers](https://www.linkedin.com/developers/apps), create an app, and add the "Sign In with LinkedIn" and "Share on LinkedIn" products.
2.  **Generate Token**: Use the included helper script to generate an OAuth 2.0 Access Token.
    ```bash
    # Set your credentials
    export LINKEDIN_CLIENT_ID="your_client_id"

Credential Access

High
Category
Privilege Escalation
Confidence
84% confidence
Finding

The configuration section explicitly requires a LinkedIn access token and a Gemini API key, confirming the skill depends on sensitive credentials. Without clear secret-handling guidance and least-privilege scope restrictions, users may expose these credentials to the environment, logs, or unrelated tools.

Content

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

text

## Configuration
- `LINKEDIN_ACCESS_TOKEN`: Valid OAuth 2.0 Access Token.
- `GEMINI_API_KEY`: Required for the Feedback Loop/Optimizer.

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/exchange_token.py (reported line 31)May include surrounding context.

python
return response.json()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Exchange LinkedIn OAuth Code for Access Token")
    parser.add_argument("code", help="The authorization code from the redirect URL")
    args = parser.parse_args()

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/linkedin_auth.py (reported line 60)May include surrounding context.

python
return response.json()

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Exchange LinkedIn OAuth Code for Access Token")
    parser.add_argument("code", help="The authorization code from the redirect URL")
    args = parser.parse_args()

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

The code path around this line culminates in displaying the full access token to the console, which is sensitive credential exposure. Even though the specific matched text is a status message, in context this operation is part of a credential disclosure flow that can leak usable bearer tokens.

Content

Scanner excerpt · scripts/exchange_token.py (reported line 38)May include surrounding context.

python
print(f"\nExchanging code: {args.code[:10]}...")
    try:
        token_data = get_access_token(args.code)
        print(f"\n✅ SUCCESS! Access Token:\n\n{token_data['access_token']}\n")
        print("Copy this token and update your .env file:")
        print(f"LINKEDIN_ACCESS_TOKEN={token_data['access_token']}")
    except Exception as e:

Credential Access

High
Category
Privilege Escalation
Confidence
99% confidence
Finding

This line instructs the user to copy the access token into .env and prints the full secret value, increasing exposure through terminal output and encouraging storage in a plaintext file. If the console output or .env file is accessible to other users, malware, backups, or logs, the token can be stolen and abused.

Content

Scanner excerpt · scripts/exchange_token.py (reported line 39)May include surrounding context.

python
try:
        token_data = get_access_token(args.code)
        print(f"\n✅ SUCCESS! Access Token:\n\n{token_data['access_token']}\n")
        print("Copy this token and update your .env file:")
        print(f"LINKEDIN_ACCESS_TOKEN={token_data['access_token']}")
    except Exception as e:
        print(f"\n❌ Error: {e}")

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/exchange_token.py (reported line 13)May include surrounding context.

python
SCOPE = "w_member_social profile openid" 

if not CLIENT_ID or not REDIRECT_URI:
    print("Error: LINKEDIN_CLIENT_ID and LINKEDIN_REDIRECT_URI must be set in .env")
    exit(1)

params = {

Credential Access

High
Category
Privilege Escalation
Confidence
60% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/get_url.py (reported line 13)May include surrounding context.

python
SCOPE = "w_member_social profile openid" 

if not CLIENT_ID or not REDIRECT_URI:
    print("Error: LINKEDIN_CLIENT_ID and LINKEDIN_REDIRECT_URI must be set in .env")
    exit(1)

params = {

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/linkedin_auth.py (reported line 36)May include surrounding context.

python
return url

def get_access_token(auth_code):
    """Exchanges the authorization code for an access token."""
    url = "https://www.linkedin.com/oauth/v2/accessToken"
    
    data = {

Credential Access

High
Category
Privilege Escalation
Confidence
70% confidence
Finding

Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Content

Scanner excerpt · scripts/linkedin_auth.py (reported line 77)May include surrounding context.

python
return url

def get_access_token(auth_code):
    """Exchanges the authorization code for an access token."""
    url = "https://www.linkedin.com/oauth/v2/accessToken"
    
    data = {

Credential Access

High
Category
Privilege Escalation
Confidence
98% confidence
Finding

This code path reveals a live access token to stdout immediately after retrieval. In the context of a LinkedIn-posting skill, that token may permit unauthorized posting or access to associated account data, making accidental disclosure particularly dangerous.

Content

Scanner excerpt · scripts/linkedin_auth.py (reported line 83)May include surrounding context.

python
access_token = token_data.get("access_token")
            expires_in = token_data.get("expires_in")
            
            print("\n✅ Access Token Generated Successfully!")
            print("-" * 60)
            print(f"Token: {access_token}")
            print("-" * 60)

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
89% confidence
Finding

The skill declares no explicit tool scope or permissions even though its documented behavior requires environment access, local file access, and network connectivity. This weakens user visibility and reviewability, making it easier for the skill to access sensitive resources such as tokens or local history files without clear upfront disclosure.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
99% confidence
Finding

The script prints the returned LinkedIn access token directly to stdout and again in an .env assignment line. Tokens printed to terminals, CI logs, shell history captures, or shared console recordings can be reused by anyone who obtains them to access the LinkedIn account within the token's scope and lifetime.

Content

No source excerpt is available for this finding.

Static analysis

No suspicious patterns detected.