mcp-server-linkedin@4.29.0
VERIFIED· not startedPublisher claims: "MCP server that gives AI assistants like Claude access to LinkedIn profiles, companies, and job postings through the user's own browser session." Observed in sandbox: no network, touches nothing outside the project, writes no memory.
Coverage
Not started: dependency install failed; the server itself was not observed.- Tested
- the dependency install step · every file read, file written and host contacted by what ran
- Not tested
- server startup · the tool list · tool behavior
What this means for the label: Verified here covers what ran. The server's tools were not exercised with a real credential, so nothing about their behavior is asserted; the credential summary below says what to do with that.
Before you give it your token
- It will ask for
- no credential variables read in the code
- Where it talks to
- linkedin.com (its own)
- What the honeypot saw
- no credential files read · no network
- What we could not test
- server startup · the tool list · tool behavior
Connect it under the guard. Not started: dependency install failed; the server itself was not observed. The code names no credential variable and talks to linkedin.com, its own; the guard pins the network to what the honeypot saw and logs every call.
Never paste a credential into a chat, a ticket or a report, including ours. How the guard holds it.
Is [email protected] safe to install?
KillerSkills ran it in the KillerSkills honeypot sandbox (2 scenarios; not started: dependency install failed; the server itself was not observed) on 2026-11-09 and scored it 81/100 (Verified). In what ran, nothing we could detect went wrong: no undeclared network egress, no credential reads, no persistent instruction writes. What it does with a real credential was not observed; the static findings and the publisher carry the rest of the score. Summary: no network, touches nothing outside the project, writes no memory.
Behavior trace
Honeypot run · 0 s · 2 scenarios · 0 deviationsStatic findings
<summary>Told to run <code>--login</code> on the host when you already did</summary> - If tool calls answer "No valid LinkedIn session is available in Docker" oFix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct.Wrong proxy credentials produce no proxy error code: Chromium retries theFix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.return subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.config = BrowserConfig(proxy_server=f"http://user:{self.SECRET}@gate:7000")Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.<summary>Told to run <code>--login</code> on the host when you already did</summary> - If tool calls answer "No valid LinkedIn session is available in Docker" oFix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct.run = subprocess.run([sys.executable, "-c", script], capture_output=True)Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."https://ci-bot:s3cr3t@[email protected]/x.zip",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."proxy_server": "http://u:p@host:8080",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.url = "https://ci-bot:[email protected]/chromium.zip"Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."linkedin_mcp_server.daemon.owner.direct_http_client",Fix: Namespace tool names and keep tool descriptions literal; no instructions to the agent inside them.completed = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.monkeypatch.setenv("PROXY_SERVER", f"http://envuser:{self.SECRET}@gate:7000")Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."plugins/linkedin-mcp-server/assets/icon.svg",Fix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.completed = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."sitecustomize: https://ci-bot:[email protected]/p?key=s3cr3t working\n"Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.<summary>Session issues</summary> - Browser profile is stored at `~/.linkedin-mcp/profile/` - Managed browser downloads are cached at `~/.linkedin-mcp/patchrighFix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct."failed via http://acctzone9:[email protected]:7000"Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."https://ci-bot:[email protected]/x.zip",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.<summary>Login issues</summary> - Make sure you have only one active LinkedIn session at a time - LinkedIn may require a login confirmation in the LinkedIn mobiFix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct.config = BrowserConfig(proxy_server="http://user:p%40ss@gate:7000")Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.<summary>Login issues</summary> - Make sure you have only one active LinkedIn session at a time - LinkedIn may require a login confirmation in the LinkedIn mobiFix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct.b"sitecustomize: https://user:[email protected]/x?token=secret\x1b[2J\n"Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.<summary>Use your own Chrome</summary> - Set **Chrome executable** in the extension's settings to a Chrome, Chromium or Chrome for Testing binary, such as `/usrFix: Remove the text that addresses the agent rather than the reader; describe behavior, do not instruct.child = subprocess.Popen([sys.executable, "-c", ""])Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.process = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.``create_mcp_server`` assembles it, with a backend whose election finds theFix: Namespace tool names and keep tool descriptions literal; no instructions to the agent inside them.self.process = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.group and kill it, so the launch was left running *and* the profile markedFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.f"stopping the child took {max(stopping):.1f}s, and a kill it "Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell."""A username with an empty password is a legitimate proxy credential.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.non-zero. ``kill -0`` keeps succeeding for a zombie, which is why waitingFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.server_term = _ENTRYPOINT.index('kill -TERM "$server_pid"')Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.assert 'sudo chown -R "$(id -u):$(id -g)" ~/.linkedin-mcp' in documentFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.started = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.("http://192.0.2.1:8080/login#x", "http://192.0.2.1:8080"),Fix: Replace encoded or assembled strings with plain literals and remove undeclared network calls.from linkedin_mcp_server.daemon.owner import direct_async_http_clientFix: Namespace tool names and keep tool descriptions literal; no instructions to the agent inside them.frontend = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# suffix and a nested directory, which is the whole of what `**/.env*` claims.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.assert 'sudo chown -R "$(id -u):$(id -g)" ~/.linkedin-mcp' in documentFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell."grandchild = subprocess.Popen([sys.executable, '-c', "Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# the run, so the kill lands on a call that has acted.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.("http://192.0.2.1:8080/login#x", "http://192.0.2.1:8080"),Fix: Replace encoded or assembled strings with plain literals and remove undeclared network calls.listing = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.child = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."subprocess.run([sys.executable, '-c', \"print('stray grandchild')\"])\n"Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.state = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# kill frontends. Entering obtain_owner here can spawn a detached ownerFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.completed = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."https://user:[email protected]/feed/",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.if subprocess.run([docker, "info"], capture_output=True, check=False).returncode:Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.("https://user:[email protected]/block", "https://filter.example"),Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.("http://192.0.2.1/login", True),Fix: Replace encoded or assembled strings with plain literals and remove undeclared network calls.self.process = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.("http://192.0.2.1/login", True),Fix: Replace encoded or assembled strings with plain literals and remove undeclared network calls.build = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.#: owner's pid and then waits, so the test can kill the owner while this processFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell."subprocess.Popen([sys.executable, sys.argv[1], sys.argv[2]])\n"Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# this, which is harmless — the second kill finds a dead child —Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.owner = subprocess.Popen([sys.executable, "-c", "import time; time.sleep(60)"])Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.#: process well before, and the bound keeps a missed kill from lasting.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.probe = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.other = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.display_term = _ENTRYPOINT.index('kill -TERM "$xvfb_pid"', server_wait)Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.# alone, where it is affordable. A kill and one wait cost 2 to 10msFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.result = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# 0755 to 0700. A custom profile directly under /tmp would try to chmodFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.AppConfig(), ["--proxy-server", f"http://u:{self.SECRET}@h:8080"]Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.from linkedin_mcp_server.daemon.owner import direct_async_http_clientFix: Namespace tool names and keep tool descriptions literal; no instructions to the agent inside them.# Pre-kill check, after the kill, at the first EPERM, at the second.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.".env.example",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.f"failed via http://{user}:{secret}@gate.example:7000",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."",Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.value = "https://ru.linkedin.com/in/%D0%B0%D0%BD%D0%B4%D1%80%D0%B5%D0%B9"Fix: Put hosts, commands and strings in plain source. Decoding at runtime looks identical to malware and costs points on its own.# chmod follows a link, so hardening one would set 0600 on whatever itFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.at the end, so neither a verdict bought with another group kill norFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell."",Fix: Replace encoded or assembled strings with plain literals and remove undeclared network calls.listing = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# A share or a FAT volume accepts chmod and keeps the old mode. WithoutFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.".env.previous-proxy",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."""The catch-all log must not carry proxy credentials.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."fix: Subject.",Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.return subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.state = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."",Fix: Replace encoded or assembled strings with plain literals and remove undeclared network calls.# scan and its kill could launch a browser the scan never saw.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell."fix: ",Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.return subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."fix(): Subject",Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent.probe = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."",Fix: Replace encoded or assembled strings with plain literals and remove undeclared network calls.gate = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out."?currentJobId=%D9%A4%D9%A2%D9%A5"Fix: Put hosts, commands and strings in plain source. Decoding at runtime looks identical to malware and costs points on its own.session cookie and proxy credentials; a real build listed it inside `/app`.Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."\u0664\u0662\u0665\u0662\u0660\u0662\u0666\u0664\u0669\u0666/"Fix: Put hosts, commands and strings in plain source. Decoding at runtime looks identical to malware and costs points on its own.".env",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.shaped = ToolError(f"failed via http://{user}:{secret}@gate.example:7000")Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.Exception(f"failed via http://{user}:{secret}@gate.example:7000"),Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.assert "chown -R pwuser:pwuser /opt/patchright" in dockerfileFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.".env.local",Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."c=subprocess.Popen([sys.executable,'-c','import time; time.sleep(600)']);"Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.listing = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.process = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.leader = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.normalize_person_identifier("%D0%B0%D0%BD%D0%B4%D1%80%D0%B5%D0%B9")Fix: Put hosts, commands and strings in plain source. Decoding at runtime looks identical to malware and costs points on its own.assert urlparse(url).path == "/in/%D0%B0%D0%BD%D0%B4%D1%80%D0%B5%D0%B9/"Fix: Put hosts, commands and strings in plain source. Decoding at runtime looks identical to malware and costs points on its own."""The loaded-macOS shape: the kill landed, waitid has not caught up.Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell."fix: ",Fix: Keep SKILL.md to visible, descriptive text. Remove comments and encoded text that address the agent."",Fix: Replace encoded or assembled strings with plain literals and remove undeclared network calls.Exception("failed via http://acctzone9:[email protected]:7000"),Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.# This ran chmod and read ls once, and that failed open: measured withFix: Request the narrowest permission that works; replace wildcards with the exact paths or hosts.answered = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.redacted = redact_proxy_credentials("http://user:s3cr3t%20p%40ss@gate:7000")Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.answer = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.holder = subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.pulled_in_the_server_graph = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.result = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.Popen(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.# #838. A WMI query on CPython 3.12 can kill the process: `_wmi`'s workerFix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell."""Rejected proxy credentials, which Chromium reports without naming a proxy."""Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.answered = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.return subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.shaped = ToolError("Proxy refused http://acctzone9:[email protected]:7000")Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose."""EPERM on the first kill means no SIGKILL reached the leader."""Fix: Build commands from fixed arguments; do not interpolate untrusted strings into a shell.result = subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.redacted = redact_proxy_credentials(f"http://{self.USERNAME}:pw@gate:7000")Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.RuntimeError(f"failed via http://{user}:{secret}@gate.example:7000"),Fix: Stop enumerating or reading credential locations; take secrets from a declared environment variable the user sets on purpose.subprocess.run(Fix: Build commands from fixed arguments, never from interpolated strings; prefer an API client over shelling out.Cost to the agent
Tokens estimated at four characters each. The tool list is re-read by the agent on every turn, so it is the number to compare between servers that do the same job: ranked across the index.
Known vulnerabilities
No advisories in OSV for mcp-server-linkedin@4.29.0 as of 5d ago. This is the package itself, not its dependencies.