Back to skill

Security audit

Omnicast

Security checks for vulnerabilities and agentic risk

Overview

OmniCast Studio is a coherent local podcast tool, but it needs Review because it under-discloses third-party AI and YouTube data flows and has risky localhost web-app vulnerabilities.

Before installing, treat this as a local web service that can send your uploaded files, URLs, transcripts, scripts, and generated media to external AI providers and can upload a private draft to YouTube after Google sign-in. Do not expose the port beyond localhost, avoid sensitive or regulated content unless you accept those provider transfers, use limited or disposable API keys where possible, and update vulnerable dependencies before relying on it with untrusted URLs or files.

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

T09 · Insecure Skill Coding Practices

Error
Location
routes/ingest.js:22
Finding
Incomplete SSRF Protection Allows Requests to Internal Network Resources<![CDATA[ ## Vulnerability Details **File Location**: `routes/ingest.js:22-49`, with vulnerable request sinks at `routes/ingest.js:70-72` and `routes/ingest.js:106` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```js const ssrfProtection = async (req, res, next) => { const { sourceType, url } = req.body; if (sourceType === 'url' && url) { try { const parsedUrl = new URL(url); // 1. Enforce safe protocols if (!['http:', 'https:'].includes(parsedUrl.protocol)) { return res.status(400).json({ error: "Security Exception: Only HTTP and HTTPS protocols are allowed." }); } const hostname = parsedUrl.hostname; // 2. Resolve the hostname to its actual IP address to prevent DNS rebinding const lookup = await dns.lookup(hostname); const resolvedIp = lookup.address; // 3. Block local and private IP ranges const isLocalOrPrivate = /^(localhost|127\.0\.0\.1|0\.0\.0\.0|10\.\d+\.\d+\.\d+|192\.168\.\d+\.\d+|172\.(1[6-9]|2[0-9]|3[0-1])\.\d+\.\d+|169\.254\.\d+\.\d+|::1)$/i.test(resolvedIp) || hostname.toLowerCase() === 'localhost'; if (isLocalOrPrivate) { return res.status(403).json({ error: "Security Exception: Access to local or private networks is strictly forbidden." }); } } catch (err) { return res.status(400).json({ error: "Security Exception: Malformed URL or DNS resolution failed." }); } } next(); }; ``` The URL is subsequently fetched without binding the request to the validated address or revalidating redirects: ```js if (lowerUrl.endsWith('.mp4')) { const tempVideoPath = path.join(sessionDir, 'downloaded.mp4'); const response = await axios({ method: 'GET', url: url, responseType: 'stream' }); const writer = fs.createWriteStream(tempVideoPath) ...[truncated 2939 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse supplied URLs with a strict URL parser and allow only `http:` and `https:`. 2. Resolve all A and AAAA records and reject the request if any result is non-public. 3. Use a maintained IP-address library rather than a regular-expression denylist. Reject loopback, private, link-local, unique-local, multicast, unspecified, reserved, documentation, carrier-grade NAT, and IPv4-mapped IPv6 ranges. 4. Disable automatic redirects, or process redirects manually and repeat complete URL and DNS validation for every destination. 5. Prevent DNS rebinding by connecting to the exact validated IP address while preserving the original hostname for the HTTP `Host` header and TLS certificate verification. 6. Apply outbound network controls at the operating-system or container level to block access to loopback, private subnets, and metadata endpoints. 7. Enforce response-size and download-time limits for both MP4 and HTML retrieval to reduce resource-exhaustion exposure. 8. Add tests covering redirects to private addresses, multiple DNS answers, IPv6 private ranges, IPv4-mapped IPv6 addresses, unusual numeric address formats, and DNS rebinding behavior. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
public/js/ui.js:58
Finding
Stored DOM Cross-Site Scripting in Live Caption Rendering<![CDATA[ ## Vulnerability Details **File Location**: `public/js/ui.js:58-68`; attacker-controlled caption content is generated at `routes/synthesize.js:36-43` and `routes/synthesize.js:99` **Vulnerability Type**: Stored DOM Cross-Site Scripting (XSS) **Risk Level**: Medium ### Vulnerable Code ```js while ((match = regex.exec(vttText)) !== null) { const startSec = timeToSeconds(match[1]); const endSec = timeToSeconds(match[2]); const speaker = match[3]; const text = match[4]; const lineDiv = document.createElement('div'); lineDiv.className = 'caption-line'; lineDiv.dataset.start = startSec; lineDiv.dataset.end = endSec; lineDiv.innerHTML = `<strong style="color: #3498db;">${speaker}:</strong> <span>${text}</span>`; ``` The values rendered above originate from script content and are written into a persistent WebVTT file without HTML escaping: ```js const sanitizedScript = script.replace(/<[^>]*>?/gm, '').replace(/\*\*/g, '').replace(/\*/g, '').replace(/^[-•]\s*/gm, '').replace(/^\d+\.\s*/gm, '').replace(/\r\n/g, '\n').trim(); const regex = /^([a-zA-Z0-9_ ]+)\s*:\s*([\s\S]*?)(?=^[a-zA-Z0-9_ ]+\s*:|\s*$)/gm; let match; const segments = []; while ((match = regex.exec(sanitizedScript)) !== null) { if (match[2].trim().length > 0) segments.push({ s: match[1].trim(), t: match[2].trim() }); } ``` ```js vttContent += `${formatVTTTime(currentTime)} --> ${formatVTTTime(currentTime + duration)}\n<v ${segments[i].s}>${lineText}\n\n`; ``` ### Technical Analysis `buildLiveCaptions()` treats the speaker name and caption text as trusted markup by interpolating them into `innerHTML`. These fields are derived from editable script content, persisted in `podcast.vtt`, and rendered whenever the generated audio or a saved session is loaded. The script cleanup removes strings matching conventional angle-bracket tags, but it is not a safe HTML sanitizer and should not be used as a security boundary. Browser parsing behavior and malformed ...[truncated 1897 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Do not render speaker names or caption text with `innerHTML`. 2. Construct the caption elements separately and assign all untrusted values through `textContent`: ```js const lineDiv = document.createElement('div'); lineDiv.className = 'caption-line'; lineDiv.dataset.start = startSec; lineDiv.dataset.end = endSec; const speakerElement = document.createElement('strong'); speakerElement.style.color = '#3498db'; speakerElement.textContent = `${speaker}:`; const textElement = document.createElement('span'); textElement.textContent = ` ${text}`; lineDiv.append(speakerElement, textElement); ``` 3. Apply strict validation to speaker names and reject unexpected control characters or WebVTT delimiters. 4. Treat script sanitization as data validation only, not as an HTML security control. 5. If rich HTML must ever be supported, use a well-maintained sanitizer with a minimal allowlist before insertion; plain `textContent` remains preferable for captions. 6. Consider a restrictive Content Security Policy that disallows inline scripts and event handlers as defense in depth. 7. Sanitize or regenerate existing session VTT files because previously stored content remains capable of reaching the vulnerable renderer. 8. Add browser tests with malicious and malformed caption payloads to verify that rendered content is always treated as text. ]]>
Vulnerability Patterns
  • Prompt InjectionInstruction Override, Hidden Instructions, Exfiltration Commands
  • 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
  • Excessive AgencyUnrestricted Tool Access, Autonomous Decision Making, Scope Creep
Findings (57)

Known Vulnerable Dependency: protobufjs==7.5.4 — 12 advisory(ies): CVE-2026-44294 (protobuf.js: Denial of service from crafted field names in generated code); CVE-2026-44293 (protobuf.js: Code injection through bytes field defaults in generated toObject c); CVE-2026-44289 (protobuf.js: Denial of service through unbounded protobuf recursion) +9 more

Critical
Category
Supply Chain
Confidence
90% confidence
Finding
protobufjs 7.5.4 is flagged with multiple severe advisories, including code injection and denial-of-service conditions. The package also shows `hasInstallScript: true`, which increases supply-chain sensitivity, and if the application parses or generates protobuf data from untrusted sources these flaws could lead to service compromise or repeated crashes.

Memory Manipulation

High
Category
Memory Poisoning
Content
res.writeHead(200, { 'Content-Type': 'text/event-stream', 'Cache-Control': 'no-cache', 'Connection': 'keep-alive' });
    state.sseClients[id] = res;
    res.write(`data: ${JSON.stringify({ message: "Connection established." })}\n\n`);
    req.on('close', () => { delete state.sseClients[id]; });
});

// Security: Explicitly bind to localhost to prevent external network access
Confidence
80% confidence
Finding
Skill manipulates agent memory, state, or stored context. Memory corruption can alter personality, override safety rules, or cause unpredictable behavior.

Known Vulnerable Dependency: axios==1.13.6 — 16 advisory(ies): CVE-2026-44494 (axios Vulnerable to Full Man-in-the-Middle via Prototype Pollution Gadget in `co); CVE-2026-44495 (axios Vulnerable to Credential Theft and Response Hijacking via Prototype Pollut); CVE-2025-62718 (Axios has a NO_PROXY Hostname Normalization Bypass that Leads to SSRF) +13 more

High
Category
Supply Chain
Confidence
86% confidence
Finding
axios 1.13.6 is flagged with multiple advisories, including SSRF-related proxy bypass and prototype-pollution-based request/response manipulation. Given this project depends on multiple network-facing libraries and likely makes outbound requests, a vulnerable HTTP client meaningfully increases risk if attacker-controlled URLs, proxy settings, or objects are used.

Known Vulnerable Dependency: brace-expansion==2.0.2 — 4 advisory(ies): CVE-2026-13149 (brace-expansion: DoS via exponential-time expansion of consecutive non-expanding); CVE-2026-33750 (brace-expansion: Zero-step sequence causes process hang and memory exhaustion); CVE-2026-14257 (brace-expansion: DoS via unbounded expansion length causing an out-of-memory pro) +1 more

High
Category
Supply Chain
Confidence
80% confidence
Finding
brace-expansion 2.0.2 is flagged for multiple algorithmic complexity and memory exhaustion issues. If any runtime path expands attacker-controlled brace patterns, this can become a denial-of-service vector; even as a transitive dependency, it is a real vulnerability presence in the supply chain.

Known Vulnerable Dependency: form-data==4.0.5 — 1 advisory(ies): CVE-2026-12143 (form-data: CRLF injection in form-data via unescaped multipart field names and f)

High
Category
Supply Chain
Confidence
82% confidence
Finding
form-data 4.0.5 is flagged for CRLF injection via unescaped multipart names/filenames. In applications that construct multipart requests using user-controlled field names or filenames, this can corrupt requests or enable header/body injection toward downstream services.

Possible Typosquatting: 'gaxios' resembles popular package 'axios'

High
Category
Supply Chain
Confidence
70% confidence
Finding
Package name closely resembles a popular package, suggesting possible typosquatting. Attackers publish malicious packages with similar names to trick developers into installing them.

Known Vulnerable Dependency: ip-address==10.1.0 — 2 advisory(ies): CVE-2026-69192 (ip-address: Address4 decodes leading-zero octets as decimal while resolvers deco); CVE-2026-42338 (ip-address has XSS in Address6 HTML-emitting methods)

High
Category
Supply Chain
Confidence
80% confidence
Finding
ip-address 10.1.0 is flagged for address parsing inconsistencies and an HTML-emitting XSS issue. Because this package is used by express-rate-limit, the parsing discrepancy could matter if IP-based trust, blocking, or allowlisting logic depends on its canonicalization behavior.

Known Vulnerable Dependency: lodash==4.17.23 — 2 advisory(ies): CVE-2025-13465 (lodash vulnerable to Prototype Pollution via array path bypass in `_.unset` and ); CVE-2021-23337 (lodash vulnerable to Code Injection via `_.template` imports key names)

High
Category
Supply Chain
Confidence
83% confidence
Finding
lodash 4.17.23 is a known vulnerable release with prototype pollution and template/code-injection history. As a broadly used utility library, unsafe use with attacker-controlled paths or templating can enable application compromise or logic manipulation.

Known Vulnerable Dependency: multer==1.4.5-lts.2 — 11 advisory(ies): CVE-2025-47935 (Multer vulnerable to Denial of Service via memory leaks from unclosed streams); CVE-2025-47944 (Multer vulnerable to Denial of Service from maliciously crafted requests); CVE-2026-82333 (multer vulnerable to Denial of Service via oversized array index in field names) +8 more

High
Category
Supply Chain
Confidence
93% confidence
Finding
multer 1.4.5-lts.2 is explicitly deprecated in the lockfile and reported with multiple DoS-class vulnerabilities. Since this project appears to handle uploads, a vulnerable multipart parser is especially risky because malformed requests can exhaust memory, leak resources, or crash the service remotely.

Known Vulnerable Dependency: path-to-regexp==8.3.0 — 2 advisory(ies): CVE-2026-4923 (path-to-regexp vulnerable to Regular Expression Denial of Service via multiple w); CVE-2026-4926 (path-to-regexp vulnerable to Denial of Service via sequential optional groups)

High
Category
Supply Chain
Confidence
80% confidence
Finding
path-to-regexp 8.3.0 is flagged for ReDoS/DoS conditions involving crafted route patterns. While the lockfile alone does not prove attacker control of route definitions, this is a legitimate dependency risk because route matching sits on the request path of an Express application and can amplify denial-of-service impact.

Known Vulnerable Dependency: undici==7.24.4 — 12 advisory(ies): CVE-2026-6733 (undici vulnerable to HTTP response queue poisoning via keep-alive socket reuse); CVE-2026-13697 (undici vulnerable to cross-user information disclosure and parse-time crash via ); CVE-2026-16728 (undici vulnerable to downstream response desynchronization via retry interceptor) +9 more

High
Category
Supply Chain
Confidence
84% confidence
Finding
undici 7.24.4 is flagged with numerous HTTP parsing, queue poisoning, and desynchronization issues. Since several listed dependencies use undici for outbound HTTP, these flaws can affect request integrity, cross-user data isolation, and stability in services that fetch remote content.

Known Vulnerable Dependency: ws==8.19.0 — 2 advisory(ies): GHSA-58qx-3vcg-4xpx; GHSA-96hv-2xvq-fx4p

High
Category
Supply Chain
Confidence
82% confidence
Finding
ws 8.19.0 is flagged by two high-severity GHSA advisories. If the application uses WebSockets directly or indirectly through AI/streaming SDKs, vulnerable frame handling or resource-management bugs may expose it to denial of service or message integrity issues.

Missing User Warnings

High
Confidence
97% confidence
Finding
This endpoint sends session text to an external AI provider based on user input, and the code shows no consent gate, data classification check, or tenant/admin control before transmitting potentially sensitive content off-system. If users place confidential or regulated text in sessions, this can cause unintended third-party data disclosure and compliance issues.

Credential Access

High
Category
Privilege Escalation
Content
const videoPath = path.join(sessionDir, 'linkedin_podcast.mp4');

    if (!accessToken) return res.status(401).json({ error: "YouTube Access Token is required." });
    if (!fs.existsSync(videoPath)) return res.status(404).json({ error: "Video not found. Please generate the video package first." });

    try {
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 geminiKey = process.env.GEMINI_API_KEY;
    
    if (!geminiKey) {
        throw new Error("GEMINI_API_KEY is missing from your .env file!");
    }
    
    // Pass the key explicitly to bypass the Vertex AI 'project' bug
Confidence
60% 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 geminiKey = process.env.GEMINI_API_KEY;
    
    if (!geminiKey) {
        throw new Error("GEMINI_API_KEY is missing from your .env file!");
    }
    
    // Pass the key explicitly to bypass the Vertex AI 'project' bug
Confidence
60% confidence
Finding
Code accesses credential files (SSH keys, AWS credentials, etc.). This could indicate credential theft attempts.

Missing User Warnings

Medium
Confidence
94% confidence
Finding
The skill description states that uploaded files, submitted URLs, and generated content are processed through external AI services via GEMINI_API_KEY and OPENAI_API_KEY, but it does not warn users that their data may be transmitted to third parties. This creates a meaningful privacy and compliance risk because users may provide sensitive media, transcripts, or URLs without informed consent or awareness of external processing.

Natural-Language Policy Violations

Medium
Confidence
95% confidence
Finding
The ingestion flow says it detects the language and translates content to English if necessary, with no indication of user choice or opt-in. Automatic translation can expose user content to additional processing, alter meaning, and create privacy, consent, and integrity issues, especially for sensitive or regulated material.

Intent-Code Divergence

Medium
Confidence
91% confidence
Finding
The comment at L21 states that static file access is being restricted strictly to localhost, but only the '/downloads' route receives that localhost check. The app also serves the 'public' directory via express.static at L19 without the same restriction, so the documentation overstates the scope of the protection actually implemented.

Context-Inappropriate Capability

Medium
Confidence
87% confidence
Finding
With no manifest available, the only available intent signal is the page's own UI. The inclusion of Google's identity client and later YouTube upload controls indicates the skill can authenticate against a third-party account and publish content externally, which is a materially sensitive capability not justified by any declared purpose in the provided context.

Natural-Language Policy Violations

Medium
Confidence
97% confidence
Finding
The button label 'Extract Text (Force English)' indicates content will be transformed into English without an explicit opt-in or clear explanation, which can override user intent and alter source meaning. For user-supplied documents, this creates a data handling and integrity risk, especially for sensitive or multilingual material where forced translation may leak, distort, or mishandle content.

Context-Inappropriate Capability

Medium
Confidence
75% confidence
Finding
The interface includes a dedicated LinkedIn section for generating a post and a ready-to-upload video. In the absence of manifest purpose or permissions, this represents social-media distribution functionality beyond a minimally inferable content-processing interface and is not justified by stated intent.

Missing User Warnings

Medium
Confidence
90% confidence
Finding
The function issues a DELETE request to '/api/delete-folder', which indicates a potentially destructive operation affecting stored data. There is no confirmation prompt, logging, comment, or other visible disclosure in this file to warn users that invoking this action may delete data.

Intent-Code Divergence

Medium
Confidence
97% confidence
Finding
The comments explicitly state that prompt wording was changed to 'satisfy security scanners' and avoid 'Prompt Injection' heuristics, which is a strong indicator of deliberate scanner-evasion behavior rather than legitimate documentation. Even though comments are non-executable, they document intent to conceal risky prompt-engineering choices from security review, increasing the likelihood that the surrounding LLM workflow is being shaped to bypass detection of unsafe behavior.

Missing User Warnings

Medium
Confidence
92% confidence
Finding
The route sends up to 3000 characters of podcast script content to an external Gemini API, which can expose sensitive or proprietary user data to a third-party processor without any visible consent, notice, or data-minimization control in this file. In a content-generation workflow, scripts may contain unpublished material, personal information, or confidential business content, so silent transmission increases privacy, compliance, and trust risks.

Static analysis

No suspicious patterns detected.