Back to skill

Security audit

Linkedin Video Downloader

Security checks for vulnerabilities and agentic risk

Overview

The skill mostly matches its stated LinkedIn video-download purpose, but its URL handling and README install examples create review-worthy security and supply-chain risk.

Review before installing. Build only from the reviewed local source, not the README placeholder GitHub path or an unpinned @latest command. Use only trusted public LinkedIn post URLs; do not expose this CLI as an automated service for arbitrary submitted URLs unless URL, redirect, response-size, and media-host validation are fixed.

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

Error
Location
main.go:63
Finding
Server-Side Request Forgery Through Insufficient URL and Redirect Validation<![CDATA[ ## Vulnerability Details **File Location**: `main.go:63-66`, `main.go:112-116`, `main.go:205-214`, `main.go:349` **Vulnerability Type**: Server-Side Request Forgery (SSRF) **Risk Level**: High ### Vulnerable Code ```go postURL := os.Args[1] printBanner() if !strings.Contains(postURL, "linkedin.com") { printError("The URL does not appear to be from LinkedIn") os.Exit(1) } ``` ```go client := &http.Client{ Timeout: 30 * time.Second, CheckRedirect: func(req *http.Request, via []*http.Request) error { req.Header.Set("User-Agent", userAgent) return nil }, } ``` ```go // Pattern 5: contentUrl in JSON-LD contentURLPattern := regexp.MustCompile(`"contentUrl"\s*:\s*"(https?://[^"]+)"`) for _, match := range contentURLPattern.FindAllStringSubmatch(html, -1) { if len(match) > 1 { cleaned := cleanURL(match[1]) if cleaned != "" && !seen[cleaned] { seen[cleaned] = true urls = append(urls, cleaned) } } } ``` ```go resp, err := client.Do(req) ``` ### Technical Analysis The application attempts to restrict input to LinkedIn by checking whether the raw argument contains the substring `linkedin.com`. This is not a valid origin check. An arbitrary URL can satisfy the condition by placing that text in its path, query string, user-information component, or attacker-controlled hostname. For example, `http://127.0.0.1:8080/?linkedin.com` passes the check while directing the HTTP request to localhost. The page-fetching client also follows redirects without validating the destination. Consequently, even a genuinely permitted origin could redirect the client to a private or otherwise prohibited address. The extracted media URL is also insufficiently constrained. In particular, the JSON-LD `contentUrl` pattern accepts any HTTP or HTTPS origin. `cleanURL` only checks whether Go can parse the value; it does not enforce an approved hostname, scheme policy beyond the regular expression, or destination IP policy. The resulting URL is subsequently req ...[truncated 1549 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Parse the supplied post URL with `url.ParseRequestURI` before any network operation. 2. Require an explicit `https` scheme and reject URLs containing user information. 3. Compare normalized hostnames against an exact allowlist, such as `www.linkedin.com`, rather than using substring matching. 4. Validate every redirect target in `CheckRedirect`; reject redirects outside the approved LinkedIn origins and impose a maximum redirect count. 5. Validate every extracted media URL against a separate, explicit CDN allowlist, such as the exact expected host or carefully implemented `licdn.com` subdomains. 6. Resolve destination hostnames and reject loopback, private, link-local, multicast, unspecified, and reserved IP ranges for every resolved address. 7. Protect against DNS rebinding by ensuring that the validated address is the address used for the connection, or by applying equivalent checks in a custom transport dialer. 8. Do not accept arbitrary JSON-LD `contentUrl` origins merely because they were present in fetched HTML. ]]>

T09 · Insecure Skill Coding Practices

Warning
Location
main.go:139
Finding
Unbounded Buffering of Remote Page Responses<![CDATA[ ## Vulnerability Details **File Location**: `main.go:139` **Vulnerability Type**: Uncontrolled Resource Consumption **Risk Level**: Medium ### Vulnerable Code ```go body, err := io.ReadAll(resp.Body) if err != nil { return "", err } return string(body), nil ``` ### Technical Analysis `io.ReadAll` buffers the complete HTTP response body in memory without enforcing a maximum page size. The HTTP client's 30-second timeout limits request duration but does not provide a reliable response-size boundary. A remote endpoint can send a very large response rapidly or continuously stream data within the permitted request period. The exposure is amplified by the weak URL validation described in the SSRF finding, because an attacker can direct the request to an attacker-controlled server while satisfying the `linkedin.com` substring check. The subsequent conversion from `[]byte` to `string` may also require additional memory, increasing peak consumption. ### Attack Path 1. An attacker supplies a URL under their control that contains `linkedin.com` in a query string, path, or another non-host component. 2. The application accepts the URL and calls `fetchPage`. 3. The remote server responds with a very large body or a chunked stream. 4. `io.ReadAll` repeatedly allocates memory while consuming the response. 5. The process experiences excessive memory usage and may be terminated by the operating system or destabilize other workloads on the same host. ### Impact Assessment A successful attack can exhaust process or system memory, terminate the downloader, and degrade other services sharing the host. The attack operates with no additional privileges beyond the ability to influence the URL passed to the CLI. In automated services that expose this downloader to remote requests, the scope may include repeated denial of service against the hosting worker or node. ]]>
Remediation
<![CDATA[ ## Remediation Suggestions 1. Define a conservative maximum HTML page size appropriate for LinkedIn post pages. 2. Reject responses whose declared `Content-Length` exceeds that limit. 3. Wrap the body with `io.LimitReader` and read at most the configured limit plus one byte so oversized responses can be detected explicitly. 4. Return an error instead of parsing a response when the limit is exceeded. 5. Preserve request timeouts and additionally configure transport-level response-header and idle timeouts. 6. Apply the strict destination validation described in the SSRF remediation so arbitrary servers cannot supply page data. Example approach: ```go const maxPageSize int64 = 10 << 20 // 10 MiB if resp.ContentLength > maxPageSize { return "", fmt.Errorf("page response exceeds size limit") } limited := io.LimitReader(resp.Body, maxPageSize+1) body, err := io.ReadAll(limited) if err != nil { return "", err } if int64(len(body)) > maxPageSize { return "", fmt.Errorf("page response exceeds size limit") } ``` ]]>

T08 · Insecure Dependencies

Warning
Location
README.md:20
Finding
Installation Instructions Reference an Unverified Mutable Placeholder Source<![CDATA[ ## Vulnerability Details **File Location**: `README.md:20-21`, `README.md:27` **Vulnerability Type**: Insecure Software Supply Chain Instructions **Risk Level**: Medium ### Vulnerable Code ```bash git clone https://github.com/yourusername/linkedin-video-dl.git cd linkedin-video-dl go build -o linkedin-video-dl . ``` ```bash go install github.com/yourusername/linkedin-video-dl@latest ``` ### Technical Analysis The installation instructions reference `github.com/yourusername/linkedin-video-dl`, which is a placeholder rather than an identified and verified canonical project location. Users following these commands may retrieve code from a namespace that is unrelated to the audited artifact or could become controlled by another party. The `go install` command also uses `@latest`, a mutable version selector. Even if the repository is initially legitimate, the code resolved in the future can differ from the version reviewed during this audit. The resulting executable therefore lacks a reliable relationship to the audited source files. No malicious external dependency is present in the reviewed Go source itself; the risk is specifically introduced by the documented installation path. ### Attack Path 1. A user follows the installation instructions in `README.md`. 2. Git or the Go toolchain resolves the placeholder repository from the external hosting service. 3. The resolved repository is controlled, registered, or later modified by a third party. 4. Because the source is not pinned to an immutable reviewed revision, the user builds or installs code that differs from this audited project. 5. The user executes the substituted binary with their local account's privileges. ### Impact Assessment If the referenced repository contains malicious code, that code executes with the privileges of the user performing the installation or running the resulting binary. It could access files and credentials available to that account, make arbitrary network request ...[truncated 285 chars]
Remediation
<![CDATA[ ## Remediation Suggestions 1. Replace `yourusername` with the verified canonical repository owner and project path. 2. Pin installation examples to a reviewed semantic version or immutable commit instead of `@latest`. 3. Publish signed releases and provide checksums for distributed binaries. 4. Protect release tags against mutation and document how users can verify signatures or checksums. 5. Ensure that the documented module path matches the module metadata and canonical source repository. 6. Update release references only after the referenced revision has undergone security review. ]]>
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 (2)

Natural-Language Policy Violations

Low
Confidence
89% confidence
Finding
The README is written in English, but the example output shown to users is in Spanish ('Obteniendo página del post...', 'Descarga completada'). This suggests the skill may present a fixed locale without offering user choice or documenting a justified locale restriction, which conflicts with the language/locale policy criteria.

Natural-Language Policy Violations

Low
Confidence
92% confidence
Finding
The request unconditionally sets `Accept-Language` to `en-US,en;q=0.5`, which imposes a specific language/locale preference in outbound requests. This is a natural-language policy concern because the skill does not offer user opt-in or explain why English is required.

Static analysis

No suspicious patterns detected.