---
title: "Find dependencies whose maintainers are compromised"
method: POST
path: "/v1/metered/dependency-risk"
tags: ["Vendor and organisation risk"]
---

# Find dependencies whose maintainers are compromised

`POST /v1/metered/dependency-risk`

## Request

- Base URL: `https://api.relayshield.net`
- URL: `https://api.relayshield.net/v1/metered/dependency-risk`
- Auth: one of:
  - API key in header `X-RS-API-KEY`
  - HTTP bearer

Every package security tool analyses the artifact. This answers the question none of them can: is the human who is able to publish that artifact compromised right now?

A self-replicating npm worm does not start with malicious code. It starts with a maintainer account, usually via an npm token lifted from an infostealer log. By the time bad code is visible in a tarball, the worm has already run. Maintainer compromise is the leading indicator.

Send a list of package names, or a `package.json` or `package-lock.json`. Each package is resolved to the accounts able to publish it, those accounts are screened against the infostealer corpus, and findings come back **at the dependency level**. Maintainer identities are never returned, logged or stored: you do not need to know who someone is in order to pin a version and require review, and naming an uninvolved third party is not something we will do.

Stealer-log recency is the alert signal. A ten-year-old breach record on a maintainer's address says nothing about whether their laptop is compromised today, so those are reported as MEDIUM context rather than as an incident.

Capped at 100 packages and 150 maintainer accounts per call. If you exceed either, `truncated` is `true` and the packages beyond the cap were **not** checked.

**Included at no per-call charge in the Agentic Attack Surface bundle** ($299/mo, through AWS Marketplace or directly). The per-call price applies only outside the bundle. Screening 400 maintainers costs us about what screening 4 does, so metering it inside the bundle would invent friction and recover nothing.

**Billing.** $0.50 per successful call. Failed calls are never billed. Charged against prepaid credits when the balance covers it, otherwise metered to your card. Threat Intelligence subscribers and AWS Marketplace bundle customers call this at no extra charge.

## Request body

- object: At least one of: `packages`, `manifest`.
  - `packages` string[]: npm package names. The recommended input: it does not hand us your full dependency graph.
  - `manifest` string: A `package.json` or `package-lock.json`, as an object or a JSON string. Easier, but it is your whole dependency graph.

## Response `200`

Success. `ok` is true and `data` holds the result.

- object
  - `ok` true, required
  - `data` object, required
    - `packages_checked` integer: Packages considered after deduplication and the cap.
    - `packages_resolved` integer: Packages the registry returned a publisher account for.
    - `maintainer_accounts_screened` integer: Distinct accounts screened. Each is screened once however many packages it publishes.
    - `role_accounts_excluded` integer: Shared or role addresses excluded from alerting. A hit on `security@` tells you nothing about one person's laptop.
    - `dependencies_at_risk` integer: Packages with any exposed publisher account.
    - `high_severity` integer: Packages whose publisher appears in a stealer log within 90 days.
    - `findings` object[]: Per-dependency findings, worst first.
      - `package` string: The dependency.
      - `severity` 'HIGH' | 'MEDIUM': HIGH is a stealer log within 90 days. MEDIUM is older, and is context.
      - `signal` string: `maintainer_in_recent_stealer_log` or `maintainer_in_older_stealer_log`.
      - `most_recent` string, nullable: Date of the most recent stealer log for any publisher of this package.
      - `detail` string: One sentence you can paste into a ticket.
    - `unresolved_packages` object[]: Packages we could not resolve, with the reason. Listed explicitly: not-resolved is not the same as not-exposed.
      - `package` string: Name.
      - `reason` string: Why.
    - `truncated` boolean: True if the call hit the package or account cap.
    - `truncated_detail` string, nullable: What was skipped, when truncated.
    - `recommended_action` string: What to do. Says the run was incomplete when it was.
    - `privacy_note` string: Restates that no maintainer identity is returned.

## Other responses

- `400`: Neither `packages` nor a parseable `manifest` was supplied.
- `401`: Missing or invalid API key.
- `402`: No credits and no active subscription. The response carries `topup_url`.
- `405`: Wrong HTTP method. Every endpoint is POST.

---

[API](https://skmtc.dev/relayshield/apis/relayshield-api.md) · [All operations](https://skmtc.dev/relayshield/apis/relayshield-api/llms.txt) · [OpenAPI document](https://skmtc.dev/relayshield/apis/relayshield-api/revisions/4d4721b936dd?raw)
