Back to skill

Security audit

instagram-digest

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its Instagram digest purpose, but it needs review because it stores Instagram session cookies in plaintext and writes untrusted Instagram/model content into local HTML without escaping.

Review before installing. Use a dedicated Instagram account, keep the skill directory private, delete scripts/.instagram_session.json when done, treat digest.html as untrusted content, and avoid processing private or sensitive reels unless you are comfortable sending transcripts and captions to OpenRouter. Pin dependencies before routine use.

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

T09 · Insecure Skill Coding Practices

Error
Location
scripts/scraper.py:75
Finding

Instagram Session State Is Persisted in Plaintext

Content
View full analysis
dict | None: """ Returns a Playwright storage_state dict (cookies + localStorage) for Instagram. - If SESSION_FILE exists, loads and returns the saved session. - Otherwise logs in fresh using config credentials and saves the session. - Returns None if no credentials are configured or login fails. """ if not config.INSTAGRAM_USERNAME or not config.INSTAGRAM_PASSWORD: return None # Reuse saved session if SESSION_FILE.exists(): print("Loading saved Instagram session.") return json.loads(SESSION_FILE.read_text(encoding="utf-8")) ``` ```python if "accounts/login" not in page.url and "challenge" not in page.url: state = ctx.storage_state() SESSION_FILE.write_text(json.dumps(state), encoding="utf-8") print(" Login successful — session saved.") return state ``` The session file is defined at line 21: ```python SESSION_FILE = Path(__file__).parent / ".instagram_session.json" ``` ### Technical Analysis Playwright storage state can contain authenticated cookies and local-storage values that function as reusable bearer credentials. The application writes this state as unencrypted JSON inside the skill directory. The write operation does not explicitly enforce restrictive file permissions, validate the destination against symbolic-link attacks, use an operating-system credential store, or establish an expiration and revocation policy. The loading path also does not verify ownership or permissions before trusting the saved file. Although default process permissions may be influenced by the operating system and the user's `umask`, the code itself does not guarantee that only the account owner can read the authentication state. Storing t ...[truncated 1418 chars]
Remediation
View remediation

T09 · Insecure Skill Coding Practices

Error
Location
scripts/emailer.py:10
Finding

Unescaped External Content Allows Stored HTML Injection in the Digest

Content
View full analysis
str: caption = reel.get("caption", "").strip() caption_line = f"

{caption[:200]}…

" if caption else "" transcript_summary = reel.get("transcript_summary", "") summary_block = f"""
Audio Summary
{transcript_summary}
""" if transcript_summary else "" return f"""
Reel · {reel.get('date','')} · {reel.get('likes',0):,} likes
{summary_block} {caption_line} View on Instagram
""" ``` Related account names are also inserted into HTML without escaping at lines 32–50: ```python def _account_section(username: str, data: dict) -> str: reels = data.get("reels", []) if not reels: return f"""

@{username}

No new reels in the lookback window.


""" reels_html = "".join(_reel_html(r) for r in reels) return f"""

Remediation
View remediation

other

Warning
Location
scripts/analyzer.py:23
Finding

Untrusted Reel Content Can Manipulate the Summarization Prompt

Content
View full analysis
str: client = _get_client() text = ( "Here is a transcript from an Instagram reel. " "Summarize it in exactly 5 bullet points. Each bullet should capture a key point. " "Be concise.\n\n" f"Transcript:\n{transcript}" + (f"\n\nCaption: {caption}" if caption else "") ) response = client.chat.completions.create( model="nvidia/nemotron-3-super-120b-a12b:free", max_tokens=512, messages=[{"role": "user", "content": text}], ) return response.choices[0].message.content ``` ### Technical Analysis The summarization instruction, transcript, and caption are concatenated into a single user message. The application does not establish a strong trust boundary between its instructions and the external content. A malicious Instagram reel can contain spoken or written instructions such as requests to ignore the summarization task and return attacker-selected material. Language models do not provide a reliable security boundary between instructions and data when both are supplied in this form. The returned value is accepted without structural validation. In this project, it is subsequently placed into HTML without escaping, making prompt injection more consequential: an attacker may attempt to make the model emit malicious markup rather than five safe bullet points. The model call has no tools, operating-system permissions, or agent-control capabilities. Therefore, this finding does not by itself provide command execution or control of the auditing agent; its direct scope is manipulation of the generated summary. ### Attack Path 1. An attacker publishes content on a tracked Instagram account or causes the skill to process an attacker- ...[truncated 1260 chars]
Remediation
View remediation
Vulnerability Patterns
  • Data ExfiltrationExternal Transmission, Env Variable Harvesting, File System Enumeration
  • Privilege EscalationExcessive Permissions, Sudo/Root Execution, Credential Access
  • Supply ChainUnpinned Dependencies, External Script Fetching, Obfuscated Code
  • MCP Least PrivilegeUnderdeclared Capability, Wildcard Permission, Missing Permission Declaration
  • MCP Tool PoisoningHidden Instructions, Unicode Deception, Parameter Description Injection
Findings (34)

Tp4

High
Category
MCP Tool Poisoning
Confidence
98% confidence
Finding

A second independent description-behavior mismatch indicates the skill may not even process recent account reels as claimed, instead operating only on a single URL and not generating summaries or digest output. Such discrepancies undermine trust and can conceal entirely different runtime behavior than what the operator expects.

Content

No source excerpt is available for this finding.

Tp4

High
Category
MCP Tool Poisoning
Confidence
95% confidence
Finding

A second independent description-behavior mismatch indicates the skill may not even process recent account reels as claimed, instead operating only on a single URL and not generating summaries or digest output. Such discrepancies undermine trust and can conceal entirely different runtime behavior than what the operator expects.

Content

No source excerpt is available for this finding.

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/config.py (reported line 5)May include surrounding context.

python
from pathlib import Path
from dotenv import load_dotenv

load_dotenv(Path(__file__).parent / ".env")

# ── Instagram accounts to track ──────────────────────────────────────────────
INSTAGRAM_ACCOUNTS = [

Undeclared Tool Scope

Medium
Category
MCP Least Privilege
Confidence
84% confidence
Finding

The skill declares environment, file, and network capabilities but does not define any explicit tool scope or permission boundaries. In an agent setting, this weakens reviewability and can allow broader-than-expected access, especially when the skill already handles credentials and external network interactions.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
91% confidence
Finding

If reel audio or transcripts are sent to OpenRouter, the absence of a clear privacy warning means users may unknowingly transfer third-party content to an external AI provider. This is particularly sensitive in a scraping skill because it combines harvested media with off-platform processing, creating legal, privacy, and compliance exposure.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Medium
Category
Not specified by scanner
Confidence
88% confidence
Finding

The documentation states output is a local digest.html, but later refers to email-sending behavior that was not disclosed earlier. Hidden or inconsistent mention of outbound communication is risky because it changes the data-flow and privacy model: users may believe data stays local when it may be transmitted elsewhere.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
94% confidence
Finding

The code sends full reel transcripts and optional captions to a third-party API provider (OpenRouter) for summarization, which creates a data-sharing path outside the local system. Even if this is functionally intended, the absence of any disclosure, consent, minimization, or provider-side safeguards can expose personal, copyrighted, or sensitive content and may violate user expectations or policy requirements.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
96% confidence
Finding

The skill’s metadata says it scrapes recent Instagram reels, but the entry point explicitly counts and reports both reels and stories. Processing stories expands collection beyond the declared scope, which can create an unauthorized data-collection/privacy issue and violates the principle of least privilege for agent skills. In this context, the mismatch makes the skill more dangerous because stories are often more ephemeral and privacy-sensitive than reels, so users reviewing the manifest may not realize that additional content types are being gathered and analyzed.

Content

No source excerpt is available for this finding.

Missing User Warnings

Medium
Category
Not specified by scanner
Confidence
89% confidence
Finding

The script persists authenticated Instagram session state to a predictable local file without any evident permission hardening, encryption, or explicit runtime consent. If another local user, process, backup system, or accidentally committed artifact accesses that file, the session cookies could be reused to impersonate the account and access data under that session.

Content

No source excerpt is available for this finding.

Description-Behavior Mismatch

Medium
Category
Not specified by scanner
Confidence
95% confidence
Finding

The skill description says it will scrape recent Instagram reels, transcribe audio, summarize with OpenRouter, and save a digest.html file. In this file, the implemented behavior is limited to scraping Instagram pages, capturing API responses, and downloading reel thumbnails; there is no audio extraction, transcription, summarization, or HTML digest creation here.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

The dependency list leaves anthropic unpinned, so installs may resolve to different versions over time, including versions with newly introduced bugs or known vulnerabilities. In a skill that processes external content and may handle API credentials, this weakens supply-chain integrity and makes builds non-reproducible.

Content

Scanner excerpt · requirements.txt (reported line 1)May include surrounding context.

text
anthropic
playwright
python-dotenv
requests

Unverifiable Dependency: anthropic has 4 known advisory(ies) (CVE-2026-34450 (Claude SDK for Python has Insecure Default File Permissions in Local Filesystem ); CVE-2026-34452 (Claude SDK for Python: Memory Tool Path Validation Race Condition Allows Sandbox); CVE-2026-34450 (The Claude SDK for Python provides access to the Claude API from Python applicat) +1 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
94% confidence
Finding

anthropic has known advisories, but because no version is pinned, it is impossible to determine whether installations are affected. This ambiguity is itself risky: the environment may resolve to a vulnerable release, and the package may handle sensitive local files or API-related operations.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

playwright is unpinned, which creates non-deterministic builds and increases exposure to supply-chain risk if a future or transitive release introduces a security issue. Because this skill automates browser activity against external sites, dependency drift can directly affect the security posture of that browser automation stack.

Content

Scanner excerpt · requirements.txt (reported line 2)May include surrounding context.

text
anthropic
playwright
python-dotenv
requests
yt-dlp

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
99% confidence
Finding

python-dotenv is unpinned, so the environment-loading component may change unexpectedly between installations and could pull in a vulnerable release. Since this package can influence how secrets are loaded from local files, version uncertainty is a meaningful supply-chain weakness.

Content

Scanner excerpt · requirements.txt (reported line 3)May include surrounding context.

text
anthropic
playwright
python-dotenv
requests
yt-dlp
faster-whisper

Unverifiable Dependency: python-dotenv has 2 known advisory(ies) (CVE-2026-28684 (python-dotenv: Symlink following in set_key allows arbitrary file overwrite via ); CVE-2026-28684 (python-dotenv reads key-value pairs from a .env file and can set them as environ)), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
95% confidence
Finding

python-dotenv has known advisories and the manifest does not constrain the installed version, leaving potential exposure unverifiable. In a project likely to load secrets from .env files, this increases the chance of unsafe file handling or secret-management issues if a vulnerable release is installed.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
99% confidence
Finding

requests is unpinned, which permits uncontrolled upgrades or resolver drift into releases with known security issues. This matters here because the skill fetches remote content, so weaknesses in HTTP handling could affect confidentiality or integrity of network interactions.

Content

Scanner excerpt · requirements.txt (reported line 4)May include surrounding context.

text
anthropic
playwright
python-dotenv
requests
yt-dlp
faster-whisper

Unverifiable Dependency: requests has 16 known advisory(ies) (CVE-2014-1830 (Exposure of Sensitive Information to an Unauthorized Actor in Requests); CVE-2024-47081 (Requests vulnerable to .netrc credentials leak via malicious URLs); CVE-2024-35195 (Requests `Session` object does not verify requests after making first request wi) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
96% confidence
Finding

requests has multiple known advisories, and without version pinning there is no assurance that deployments avoid affected versions. Because this skill retrieves external resources, a vulnerable HTTP client could expose credentials, mishandle redirects, or weaken transport-related trust decisions.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
99% confidence
Finding

yt-dlp is unpinned, creating supply-chain uncertainty around a package that processes attacker-controlled remote media and extractor logic. In this skill context, that is somewhat more dangerous than a generic library because the tool interacts with untrusted online content and has a history of security advisories.

Content

Scanner excerpt · requirements.txt (reported line 5)May include surrounding context.

text
playwright
python-dotenv
requests
yt-dlp
faster-whisper

Unverifiable Dependency: yt-dlp has 16 known advisory(ies) (CVE-2023-46121 (yt-dlp Generic Extractor MITM Vulnerability via Arbitrary Proxy Injection); GHSA-3v33-3wmw-3785 (yt-dlp has dependency on potentially malicious third-party code in Douyu extract); CVE-2023-40581 ( yt-dlp on Windows vulnerable to `--exec` command injection when using `%q`) +13 more), but the manifest does not pin a version, so it is unknown whether the installed release is affected

Low
Category
Supply Chain
Confidence
97% confidence
Finding

yt-dlp has a substantial advisory history, and the lack of version pinning makes it impossible to verify whether the installed release is safe. This is more concerning in this skill because yt-dlp processes untrusted remote media sources and extractor behavior, increasing the practical attack surface.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
97% confidence
Finding

faster-whisper is unpinned, so deployments may silently pick up differing code with unreviewed security characteristics. For a transcription pipeline that handles downloaded media, reproducibility and version review are important to reduce supply-chain risk.

Content

Scanner excerpt · requirements.txt (reported line 6)May include surrounding context.

text
python-dotenv
requests
yt-dlp
faster-whisper

Missing User Warnings

Low
Category
Not specified by scanner
Confidence
91% confidence
Finding

This code accesses Instagram and OpenRouter credentials via environment variables, which falls under sensitive environment variable or credential handling. While there are comments about account setup, there is no explicit user-facing warning, confirmation, or disclosure in this file about reading and using these secrets.

Content

No source excerpt is available for this finding.

Intent-Code Divergence

Low
Category
Not specified by scanner
Confidence
97% confidence
Finding

The manifest says the skill summarizes with OpenRouter, but the generated HTML footer explicitly says "Powered by Claude." This is an intent/documentation contradiction in user-visible output about what system produced the digest.

Content

No source excerpt is available for this finding.

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The dependency list leaves the openai package unpinned, so installations may silently pull different versions over time. This weakens build reproducibility and can expose the skill to newly introduced vulnerable or incompatible releases through the software supply chain.

Content

Scanner excerpt · scripts/requirements.txt (reported line 1)May include surrounding context.

text
openai
playwright
python-dotenv
requests

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
95% confidence
Finding

The playwright dependency is unpinned, allowing future installs to resolve to arbitrary newer releases. In an automation-heavy skill that drives a browser, unpredictable dependency drift increases the risk of pulling a compromised or vulnerable version and makes incident response harder.

Content

Scanner excerpt · scripts/requirements.txt (reported line 2)May include surrounding context.

text
openai
playwright
python-dotenv
requests
yt-dlp

Unpinned Dependencies

Low
Category
Supply Chain
Confidence
98% confidence
Finding

python-dotenv is unpinned despite having known advisories in some releases, so the manifest cannot demonstrate that affected versions are excluded. This creates avoidable supply-chain ambiguity and may allow installation of a vulnerable version depending on when the environment is built.

Content

Scanner excerpt · scripts/requirements.txt (reported line 3)May include surrounding context.

text
openai
playwright
python-dotenv
requests
yt-dlp
faster-whisper

Static analysis

No suspicious patterns detected.