Skip to main content
Glama

hackerone-mcp

A stdio MCP server that helps a bug-bounty hacker prepare HackerOne report drafts locally. It reads program information from the HackerOne Hacker API (read-only) and stores drafts as files on your machine.

Non-goal: it never submits anything

This server does not submit, send, or publish reports, and it is built so that it cannot:

  • The only HTTP client code lives in src/client/ and only issues GET requests to the fixed origin https://api.hackerone.com.

  • There is no submit tool. A test (src/tools/guard_tests.rs) pins the exact set of 12 tools and asserts no tool name contains submit, send, post, publish, upload or report_remote.

  • draft_validate only shows a preview of the request body that would be sent; it is marked never_sent.

You review the draft and submit it yourself in the HackerOne web UI.

Related MCP server: h1-brain

Tools

Tool

Description

Parameters

program_list

List programs visible to your account (needs credentials)

page, page_size

program_get

Get one program incl. policy and submission state

handle

program_scope

List a program's structured scopes (assets)

handle, page, page_size, id_gt, created_at_gt, updated_at_gt

program_scope_exclusions

List scope exclusions (report categories excluded from rewards)

handle

program_weaknesses

List weaknesses (CWE types) the program accepts

handle, page, page_size

program_submission_options

Derived summary: submission state, scopes, accepted weaknesses

handle

draft_create

Create a local draft

title, vulnerability_information, team_handle, impact, severity_rating, weakness_id, structured_scope_id, cwe, cvss_vector, affected_versions, references, notes, id

draft_get

Read a draft

id

draft_update

Update fields; optimistic locking and field clearing

id, expected_revision, any create field, clear

draft_list

List draft summaries, newest first

limit (default 50, max 200)

draft_delete

Delete a local draft file

id, expected_revision

draft_validate

Offline validation plus a request-body preview (never sent)

id

The program_* tools need HackerOne credentials; the draft_* tools work without them. weakness_id and structured_scope_id are HackerOne's integer ids (take them from program_submission_options), not CWE numbers.

Running with Docker

The server is distributed as a container image and is started over stdio, so the MCP client runs docker run -i.

Image: ghcr.io/tkgstrator/hackerone-mcp, platforms linux/amd64 and linux/arm64. Tags per release: X.Y.Z, vX.Y.Z, latest and sha-<full commit SHA>. Pin an explicit version in your client config rather than latest.

The first push to GHCR creates the package as private. Until the owner has made it public once (manually, in the package settings), pull it after docker login ghcr.io with a token that has read:packages.

docker pull ghcr.io/tkgstrator/hackerone-mcp:<version>
docker run -i --rm -v hackerone-mcp-drafts:/data/drafts ghcr.io/tkgstrator/hackerone-mcp:<version>

The command above is draft-only (no credentials). To enable the program_* tools pass credentials as described under Configuration.

Image details

  • Runtime is gcr.io/distroless/cc-debian12 (no shell); the entrypoint is the binary.

  • It runs as non-root uid/gid 10001. /data/drafts is pre-created with mode 0700, owned by 10001, declared as a VOLUME, and H1_MCP_DRAFTS_DIR=/data/drafts is preset.

  • Named volumes (-v hackerone-mcp-drafts:/data/drafts) need no setup: they inherit the right owner and mode.

  • Bind mounts must satisfy the same rules, because the server refuses a drafts directory that is accessible by group/other (drafts directory is accessible by group/other (expected mode 0700)) or not owned by the container user (cannot stat drafts directory: Permission denied). Prepare the host directory first:

    mkdir -p "$HOME/hackerone-drafts"
    chown 10001:10001 "$HOME/hackerone-drafts" && chmod 700 "$HOME/hackerone-drafts"   # may need sudo
    docker run -i --rm -v "$HOME/hackerone-drafts:/data/drafts" ghcr.io/tkgstrator/hackerone-mcp:<version>

    Running with --user "$(id -u):$(id -g)" instead is not verified and did not work on Docker Desktop / OrbStack because of ownership mapping.

  • The filesystem behind /data/drafts must support hard links (named volumes do).

Configuration

Environment variables:

Variable

Meaning

H1_USERNAME

HackerOne API username. Only needed for program_* tools.

H1_API_KEY

HackerOne API token. Only needed for program_* tools. Must be set together with H1_USERNAME.

H1_MCP_DRAFTS_DIR

Directory for drafts. Preset to /data/drafts in the image.

Without credentials the server still starts and the draft tools work; program_* tools return a clear configuration error.

Registering with an MCP client

Do not put the token in command-line arguments or in a config file that is world-readable: arguments are visible to other local users via ps, and client config files are often synced or committed. Keep the secrets in a file only you can read and hand it to Docker with --env-file (Docker reads it; the values never appear in the command line). Alternatively use value-less -e H1_USERNAME -e H1_API_KEY, which copies the variables from the environment of the launching process, so the values are still not in argv.

# secrets file, readable only by you
mkdir -p ~/.config/hackerone-mcp
install -m 600 /dev/null ~/.config/hackerone-mcp/env
$EDITOR ~/.config/hackerone-mcp/env     # add the two lines below
#   H1_USERNAME=your-username
#   H1_API_KEY=your-token

Claude Code:

claude mcp add hackerone -- docker run -i --rm \
  -v hackerone-mcp-drafts:/data/drafts \
  --env-file "$HOME/.config/hackerone-mcp/env" \
  ghcr.io/tkgstrator/hackerone-mcp:<version>

Claude Desktop (claude_desktop_config.json; use an absolute path, $HOME is not expanded):

{
	"mcpServers": {
		"hackerone": {
			"command": "docker",
			"args": [
				"run", "-i", "--rm",
				"-v", "hackerone-mcp-drafts:/data/drafts",
				"--env-file", "/Users/you/.config/hackerone-mcp/env",
				"ghcr.io/tkgstrator/hackerone-mcp:<version>"
			]
		}
	}
}

For draft-only use, drop the --env-file option; no credentials are needed.

Release archives

Each GitHub release also carries hackerone-mcp-vX.Y.Z-<target>.tar.gz archives (binary, LICENSE, README.md) for aarch64-apple-darwin, x86_64-apple-darwin, x86_64-unknown-linux-gnu and aarch64-unknown-linux-gnu, plus SHA256SUMS. They are attested; verify with:

gh attestation verify <archive> --repo tkgstrator/hackerone-mcp
shasum -a 256 -c SHA256SUMS

The Linux archives are built in the Debian bookworm toolchain; the binary's highest required glibc symbol version is 2.34 (measured). Docker is the documented way to run the server.

Draft file format

Each draft is <id>.md in the drafts directory: TOML frontmatter between +++ lines, then the Markdown body (the report's vulnerability_information). Ids match [a-z0-9-]{1,64}.

+++
id = "example-xss"
revision = 1
created_at = 1792838334
updated_at = 1792838334
status = "draft"
team_handle = "acme"
title = "Stored XSS in profile bio"
impact = "Account takeover"
severity_rating = "high"
cwe = "cwe-79"
cvss_vector = "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:C/C:H/I:L/A:N"
affected_versions = "< 2.4.1"
references = ["https://example.com/advisory"]
+++
## Steps
1. Open profile

revision increases on every update; pass expected_revision to draft_update/draft_delete to avoid overwriting concurrent edits.

Draft tool outputs return the full body, up to the 200,000-byte body limit. Only a hand-edited file whose body exceeds that limit is returned truncated; the result then carries a server-generated top-level body_truncation object (truncated, returned_bytes, total_bytes, warning) outside the draft fields, and such a body must not be written back with draft_update.

Workflow

  1. program_submission_options for the target program (submission state, scope ids, weakness ids).

  2. draft_create, then refine with draft_update.

  3. draft_validate for an offline check of the required fields and a preview of the request body. It does not prove you are allowed to submit to the program.

  4. Copy the draft into the HackerOne web UI and submit it there, manually.

For CVE preparation the drafts carry cwe, cvss_vector and affected_versions. These are local notes only. CVE IDs are assigned by a CNA (the vendor, a CNA-of-last-resort, or MITRE), never by this tool.

Security notes

  • Token handling: the API key is read from the environment, redacted in Debug output, and is not written to stdout or stderr (checked by tests/stdio_e2e.rs). Use a 0600 env file as above.

  • Data flows to your LLM client: tool results, including draft contents and program data, are sent to whatever model your MCP client uses. Do not store secrets in drafts.

  • Untrusted text: program policies, scope descriptions and other API-derived text are attacker-influenced. Responses are labelled as untrusted, but a model can still be prompt-injected by such text; review what the model does and writes.

  • Files: Unix only. The drafts directory is created with mode 0700 and draft files with 0600. New drafts are created atomically using hard_link, so the drafts directory must be on a filesystem that supports hard links.

  • Dependencies: HTTP is reqwest with rustls only (no OpenSSL / native-tls). deny.toml bans alternative HTTP clients and TLS stacks, restricts licenses and sources. CI also checks that no direct dependency on hyper or other HTTP client crates is declared.

Development

Building from source requires Rust 1.89 or newer (edition 2024). Unix only (macOS, Linux).

cargo build --release           # binary at target/release/hackerone-mcp
cargo fmt --check
cargo clippy --all-targets -- -D warnings
cargo test
cargo deny check
cargo audit
docker build -t hackerone-mcp:local .
scripts/docker-smoke.sh hackerone-mcp:local   # needs docker and jq
bun install --frozen-lockfile --ignore-scripts && bunx commitlint --last --verbose

tests/stdio_e2e.rs spawns the real binary and talks JSON-RPC over stdio. scripts/docker-smoke.sh starts the image, checks initialize, that tools/list returns 12 tools, and a draft_create / draft_get round trip.

Commits

Use Conventional Commits. CI commitlint checks PR commits and non-master branch push tips; it skips normal GitHub merge commits on master. Configuration is in .commitlintrc.yaml, with dependencies pinned in bun.lock. Allowed types: build, ui, ci, docs, feat, fix, perf, refactor, revert, format, test, chore; header up to 128 characters.

CI (.github/workflows/integration.yaml)

Runs on pull requests, branch pushes, master pushes, and manual dispatch. On master, all checks must pass before it calls the reusable Deployment workflow for the same commit:

  • Integration / Commit Lint

  • Integration / rustfmt

  • Integration / Clippy (ubuntu-latest) and Integration / Clippy (macos-latest)

  • Integration / Test (ubuntu-latest) and Integration / Test (macos-latest)

  • Integration / Supply chain: cargo deny, cargo audit, and a guard against direct HTTP-client dependencies

  • Integration / Docker (amd64) and Integration / Docker (arm64): build each native-platform image (no push) and run scripts/docker-smoke.sh

Branch protection on master is expected to require these checks to pass before merge and to disallow direct and force pushes (a repository setting, not enforced by files in this repo).

All third-party GitHub Actions are pinned to commit SHAs. Dependabot (.github/dependabot.yml) proposes weekly updates for GitHub Actions, Cargo, Docker and Bun (package.json / bun.lock).

Releasing (.github/workflows/deployment.yaml)

  1. For the first release, merge the release workflow to master. For subsequent releases, bump version in Cargo.toml and merge to master through a pull request. The version must be plain MAJOR.MINOR.PATCH; prerelease and build suffixes (-rc.1, +build) are not supported.

  2. Successful Integration checks call Deployment at that same commit. Deployment builds the four archives, then pushes the multi-arch image under a commit-SHA tag. After verifying the archives, checksums and draft release, and generating attestations, it points the version and latest tags at the exact image digest and publishes the GitHub release.

Behaviour to know about:

  • Deployment checks that its tested commit is still the master head before the image push, before moving version tags, and before publishing the release. A new push between a check and publication can still race; check the final tag and image after release.

  • A push that does not change the version is a green no-op once a release for that version is published.

  • A tag vX.Y.Z that exists at another commit without a published release fails the run visibly; fix or delete the tag manually.

  • Version and latest image tags are updated only after the draft assets are verified. GHCR and GitHub Releases are separate services: a failure after tag promotion can leave image tags before the release appears. Inspect the state before retrying Integration on master.

  • A failed upload or publication can leave a draft release. A retry refuses to overwrite any draft with the same tag, including one written by a person. Inspect its assets and notes, then remove that draft manually before retrying. The workflow never deletes a draft automatically.

  • [skip ci] / [ci skip] suppresses the automatic run; dispatch Integration on master manually to run all checks and publish. The first GHCR push creates a private package; make it public in the package settings if anonymous pulls are required, then verify without Docker credentials.

License

MIT, see LICENSE.

Related MCP Connectors

Related MCP Servers

  • F
    license
    A
    quality
    D
    maintenance
    Provides read-only access to HackerOne reports, program scopes, and bounty earnings through the HackerOne API. It enables users to analyze hunting patterns, check asset eligibility, and retrieve report details or triage conversations via natural language.
    9
    46 npm
    41
    -
  • A
    license
    Not graded
    quality
    C
    maintenance
    Connects AI assistants to HackerOne to pull bug bounty history, program scopes, and report details into a local SQLite database, exposing tools for searching, analyzing, and generating attack briefings using both personal and public disclosed reports.
    355
    MIT
  • F
    license
    A
    quality
    D
    maintenance
    A local, read-only MCP server that connects your HackerOne researcher account to Claude Desktop and Claude Code, helping you find targets, analyze program scopes, review reports and earnings, and draft bug reports.
    17
    4
    -