Skip to content

Public API

Access AI Sec Watch data programmatically. All endpoints return JSON with CORS enabled, so you can call them from any domain.

Base URL
/api/v1
Rate limit
60 req/min per IP
CORS
* (all origins)

Start here

  1. 1.Check a project's dependency files

    Send manifests, lockfiles or an SBOM to Stack Check and get the vulnerabilities in the pinned versions, the LLM components and the authority the dependencies grant. Add ?format=markdown for a Markdown report or ?format=cyclonedx for a CycloneDX 1.6 AI-BOM. Files are not stored. POST /api/v1/check reference

    Shell
    curl -X POST "https://aisecwatch.com/api/v1/check" \
      -H "Content-Type: application/json" \
      -d '{
        "files": [
          { "filename": "requirements.txt", "content": "langchain==0.1.0\n" }
        ]
      }'
  2. 2.Look up packages and vendors by name

    Send package and vendor names in one request and get matching issues with a severity histogram. Matching is by name, not by version. POST /api/v1/scan reference

    Shell
    curl -X POST "https://aisecwatch.com/api/v1/scan" \
      -H "Content-Type: application/json" \
      -d '{
        "packages": ["langchain", "llama-index"],
        "vendors": ["OpenAI", "Anthropic"],
        "severityMin": "high"
      }'
  3. 3.Call the API

    List issues with filters and pagination. Reads need no key and work from any origin. GET /api/v1/issues reference

    Shell
    curl "https://aisecwatch.com/api/v1/issues?severity=critical&limit=10" \
      -H "Accept: application/json"
  4. 4.Add the MCP server

    Register the MCP endpoint in your coding agent's configuration so it can run Stack Check, look up a package in the Exposure Registry and search issues. MCP setup

    JSON
    {
      "mcpServers": {
        "aisecwatch": {
          "type": "http",
          "url": "https://aisecwatch.com/api/mcp"
        }
      }
    }

Quick start in Python, R and curl

import pandas as pd

# Load full dataset (CSV)
df = pd.read_csv("https://aisecwatch.com/api/issues/export")

# Or use the JSON API with filtering
import requests

resp = requests.get("https://aisecwatch.com/api/v1/issues", params={
    "severity": "critical",
    "limit": 100,
})
data = resp.json()["data"]

No API key is required. The limit is 60 requests per minute, and all data is licensed CC-BY-4.0.

Endpoints

MethodPathDescription
POST/api/v1/checkStack Check. Send the text of up to 5 dependency files and get a report: known vulnerabilities in the pinned versions (from OSV) with fixed versions, the LLM SDKs, agent frameworks, MCP and retrieval components in the tree, dependencies that reach one indirectly, the host authority the dependencies grant, and the controls that follow. Lockfiles give version-exact results. Files are processed in memory and not stored. This endpoint allows 10 requests per minute per IP.
GET/api/v1/packagesSearch the Exposure Registry: open-source packages on PyPI, npm, crates.io and Go, with the date and version in which each first declared an LLM SDK, agent framework or MCP dependency, the SDKs it declares, its authority profile and the number of advisories that name it. By default the list holds packages that declare such a dependency or reach one through their own dependencies.
GET/api/v1/packages/:ecosystem/:nameGet one package's record in the Exposure Registry: the date and version in which it first declared an LLM dependency, the SDKs it declares, its authority profile and the dependencies behind it, the dependency path to an LLM package when the exposure is transitive, the dependencies of its latest release, and the advisories that name it. Advisories are matched by package name and by the ecosystem the advisory source states. An advisory with no ecosystem recorded for the package is matched by name alone and carries matchedBy "name". A package not yet in the registry returns 202 and is queued.
GET/api/v1/issuesList relevant, processed security issues with optional filtering and pagination.
GET/api/v1/issues/:idGet a single issue by its UUID, CVE identifier or GHSA identifier. Returns 404 if not found or not relevant.
GET/api/v1/advisories/:idLook up one record by identifier. The identifier can be a CVE identifier, a GHSA identifier or the record's UUID, and CVE and GHSA identifiers match in any letter case. Returns the same payload as /api/v1/issues/:id, and 404 when no published record carries the identifier.
GET/api/v1/topicsList the topic catalog with each topic's matching patterns and current counts. Pass a topic's key as the topic parameter of /api/v1/issues to list its items.
GET/api/v1/digest/latestGet the latest daily TLDR digest. Falls back to the most recent non-empty digest.
POST/api/v1/scanLook up issues by package name or vendor name. Accepts a list of package names and/or vendor names and returns matching issues plus a severity histogram. Use this instead of chaining multiple filtered /issues calls. Matching is by name, not by version. To check the versions a project pins, use POST /api/v1/check.
GET/api/v1/issues/stixExport issues as a STIX 2.1 bundle. Compatible with MISP, OpenCTI, ThreatConnect, and other threat intelligence platforms.
GET/api/v1/statsGet aggregate platform statistics.
POST/api/v1/webhooksCreate a webhook to receive a notification after each fetch cycle in which new issues match your filters. Requires WEBHOOK_API_KEY bearer auth. Payloads are signed with HMAC-SHA256.

POST/api/v1/check

Stack Check. Send the text of up to 5 dependency files and get a report: known vulnerabilities in the pinned versions (from OSV) with fixed versions, the LLM SDKs, agent frameworks, MCP and retrieval components in the tree, dependencies that reach one indirectly, the host authority the dependencies grant, and the controls that follow. Lockfiles give version-exact results. Files are processed in memory and not stored. This endpoint allows 10 requests per minute per IP.

Parameters

NameTypeDescription
filesobject[] (body)Required. One to five objects of the form { "filename": "poetry.lock", "content": "<the file text>" }. Supported: package.json, package-lock.json, npm-shrinkwrap.json, pnpm-lock.yaml, yarn.lock, requirements.txt, pyproject.toml, poetry.lock, uv.lock, Pipfile.lock, go.mod, go.sum, Cargo.toml, Cargo.lock, and CycloneDX or SPDX JSON SBOMs. Manifests and lockfiles can be up to 2 MB each and SBOMs up to 5 MB, within 6 MB for the whole request.
osvboolean (body)Look up vulnerabilities in OSV (default true). The lookup sends package names and pinned versions to osv.dev. Set it to false to skip the lookup.
formatstring (query)Omit for the JSON report. "markdown" returns the report as Markdown. "cyclonedx" returns a CycloneDX 1.6 AI-BOM with the LLM components, the dependencies that reach one indirectly and the vulnerabilities found.

Example response

// Request
POST /api/v1/check
Content-Type: application/json
{
  "files": [
    { "filename": "requirements.txt", "content": "langchain==0.1.0\n" }
  ]
}

// Response
{
  "data": {
    "files": [
      {
        "filename": "requirements.txt",
        "kind": "requirements.txt",
        "ecosystem": "pypi",
        "dependencies": 1,
        "warnings": []
      }
    ],
    "summary": {
      "dependencies": 1,
      "direct": 1,
      "pinned": 1,
      "llmComponents": 1,
      "viaDependency": 0,
      "vulnerabilities": 1,
      "vulnerablePackages": 1,
      "authority": []
    },
    "llmComponents": [
      {
        "ecosystem": "pypi",
        "name": "langchain",
        "version": "0.1.0",
        "versionSpec": "==0.1.0",
        "direct": true,
        "keys": ["langchain"],
        "categories": ["agent_framework"]
      }
    ],
    "viaDependency": [],
    "authority": { "profile": [], "fromDependencies": [] },
    "vulnerabilities": [
      {
        "id": "GHSA-xxxx-xxxx-xxxx",
        "aliases": ["CVE-2026-1234"],
        "summary": "Critical prompt injection in LangChain",
        "severity": "critical",
        "cvss": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
        "cwes": ["CWE-77"],
        "fixedVersions": ["0.1.1"],
        "published": "2026-02-08T00:00:00Z",
        "references": ["https://github.com/advisories/GHSA-xxxx-xxxx-xxxx"],
        "package": { "ecosystem": "pypi", "name": "langchain", "version": "0.1.0", "direct": true },
        "record": {
          "url": "https://aisecwatch.com/issues/a1b2c3d4-...",
          "severity": "critical",
          "epssScore": 0.87,
          "exploitMaturity": "active"
        }
      }
    ],
    "controls": [
      {
        "id": "patch-vulnerable",
        "title": "Upgrade the dependencies with known vulnerabilities",
        "why": "At least one pinned version is affected by a published advisory.",
        "actions": [ ... ],
        "references": [{ "label": "OSV vulnerability database", "url": "https://osv.dev/" }],
        "trigger": "vulnerability findings on pinned versions"
      },
      {
        "id": "prompt-injection",
        "title": "Treat everything the model reads as untrusted input",
        "why": "Agent frameworks act on content from documents, web pages and tool results, where injected instructions hide.",
        "actions": [ ... ],
        "references": [ ... ],
        "trigger": "agent framework present"
      }
    ],
    "notes": [],
    "generatedAt": "2026-03-12T12:00:00.000Z"
  },
  "meta": { "privacy": "Files were processed in memory and not stored." }
}

// With ?format=markdown the body is the same report as Markdown (text/markdown).
// With ?format=cyclonedx the body is a CycloneDX 1.6 AI-BOM (application/vnd.cyclonedx+json).

GET/api/v1/packages

Search the Exposure Registry: open-source packages on PyPI, npm, crates.io and Go, with the date and version in which each first declared an LLM SDK, agent framework or MCP dependency, the SDKs it declares, its authority profile and the number of advisories that name it. By default the list holds packages that declare such a dependency or reach one through their own dependencies.

Parameters

NameTypeDescription
qstringMatch part of the package name
ecosystemstringOne of "pypi", "npm", "go", "cargo"
exposurestring"direct" (declares an LLM dependency), "transitive" (reaches one through dependencies), "none", or "any" for every tracked package. Default: direct and transitive.
sdkstringCatalog key of an SDK or framework the package declares (e.g. "openai", "langchain", "mcp")
authoritystringAuthority kind in the package profile: "execution", "filesystem", "shell", "browser", "http", "mcp_tools"
sortstring"integrated" (most recent LLM integration first, the default), "name" or "advisories"
pagenumberPage number (default 1)
perPagenumberResults per page (default 50, max 100)

Example response

{
  "data": [
    {
      "ecosystem": "pypi",
      "name": "example-agent",
      "url": "https://aisecwatch.com/packages/pypi/example-agent",
      "latestVersion": "2.4.0",
      "exposure": "direct",
      "depth": 0,
      "integratedAt": "2024-03-14T09:30:00.000Z",
      "integratedVersion": "1.2.0",
      "sdks": ["langchain", "openai"],
      "authority": ["http", "shell"],
      "advisoryCount": 1
    }
  ],
  "meta": {
    "total": 120,
    "page": 1,
    "perPage": 50,
    "totalPages": 3
  }
}

GET/api/v1/packages/:ecosystem/:name

Get one package's record in the Exposure Registry: the date and version in which it first declared an LLM dependency, the SDKs it declares, its authority profile and the dependencies behind it, the dependency path to an LLM package when the exposure is transitive, the dependencies of its latest release, and the advisories that name it. Advisories are matched by package name and by the ecosystem the advisory source states. An advisory with no ecosystem recorded for the package is matched by name alone and carries matchedBy "name". A package not yet in the registry returns 202 and is queued.

Parameters

NameTypeDescription
ecosystemstring (path)One of "pypi", "npm", "go", "cargo"
namestring (path)Package name. A scoped npm name takes two path segments (npm/@scope/name), and a Go module keeps its path (go/github.com/owner/module).

Example response

{
  "data": {
    "ecosystem": "pypi",
    "name": "example-agent",
    "url": "https://aisecwatch.com/packages/pypi/example-agent",
    "latestVersion": "2.4.0",
    "firstReleaseAt": "2023-06-01T10:00:00.000Z",
    "repository": "https://github.com/example/example-agent",
    "llm": {
      "exposure": "direct",
      "depth": 0,
      "integratedAt": "2024-03-14T09:30:00.000Z",
      "integratedVersion": "1.2.0",
      "sdks": ["langchain", "openai"],
      "path": []
    },
    "authority": {
      "profile": ["http", "shell"],
      "fromDependencies": ["pypi:requests", "pypi:sh"]
    },
    "dependencies": [
      { "ecosystem": "pypi", "name": "langchain", "versionSpec": ">=0.2", "scope": "runtime" }
    ],
    "advisories": [
      {
        "id": "a1b2c3d4-...",
        "url": "https://aisecwatch.com/issues/a1b2c3d4-...",
        "cveId": "CVE-2026-1234",
        "title": "Command injection in example-agent",
        "severity": "high",
        "publishedAt": "2026-02-10T12:00:00.000Z",
        "affected": ["example-agent@< 2.3.1 (fixed: 2.3.1)"],
        "epssScore": 0.02,
        "matchedBy": "ecosystem"
      }
    ],
    "checkedAt": "2026-03-12T06:30:00.000Z"
  },
  "meta": {
    "advisoryMatching": "by package name and ecosystem; an advisory with no ecosystem recorded for the package is matched by name alone"
  }
}

// A package not yet in the registry (202)
{
  "data": { "ecosystem": "pypi", "name": "example-agent", "status": "queued" },
  "meta": {
    "note": "Not yet in the registry; it has been queued and is usually available within a day."
  }
}

GET/api/v1/issues

List relevant, processed security issues with optional filtering and pagination.

Parameters

NameTypeDescription
searchstringSearch issues by title, headline, summary and CVE ID
labelstringFilter by label (e.g. "security", "privacy", "research", "safety")
severitystringFilter by severity (e.g. "critical", "high", "medium", "low")
issueTypestringFilter by issue type: "vulnerability", "incident", "news", "regulatory", "research"
vendorstringFilter by affected vendor (e.g. "OpenAI", "Anthropic", "Google", "LangChain")
packagestringFilter by affected package (e.g. "langchain", "llama-index"). The name is normalized before matching: lower case, with runs of "-", "_" and "." treated alike.
topicstringFilter by topic key from /api/v1/topics (e.g. "mcp", "prompt-injection"). An unknown key returns 400.
sinceISO 8601 dateOnly return issues published after this date
limitnumberResults per page (default 20, max 100)
offsetnumberNumber of results to skip (default 0)
confidenceMinnumberMinimum classifier confidence 0-1 (e.g. 0.8 for >80%)

Example response

{
  "data": [
    {
      "id": "a1b2c3d4-...",
      "title": "Critical prompt injection in LangChain",
      "summary": "A critical vulnerability was found...",
      "sourceUrl": "https://...",
      "publishedAt": "2026-02-10T12:00:00.000Z",
      "severity": "critical",
      "cvssSeverity": "CRITICAL",
      "cvssScore": "9.8",
      "labels": ["security"],
      "issueType": "vulnerability",
      "cveId": "CVE-2026-1234",
      "cweIds": ["CWE-77"],
      "affectedPackages": ["langchain"],
      "affectedVendors": ["LangChain"],
      "affectedVendorsRaw": ["LangChain", "OpenAI"],
      "classifierModel": "claude-haiku-4-5-20251001",
      "classifierPromptVersion": "v3",
      "solution": "Upgrade to v0.1.1 or later",
      "attackType": ["prompt_injection"],
      "cvssVector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
      "attackVector": "network",
      "attackComplexity": "low",
      "privilegesRequired": "none",
      "userInteraction": "none",
      "exploitMaturity": "active",
      "epssScore": 0.87,
      "patchAvailable": true,
      "disclosureDate": "2026-02-08T00:00:00.000Z",
      "capecIds": ["CAPEC-242"],
      "crossRefCount": 3,
      "attackSophistication": "moderate",
      "impactType": ["confidentiality", "integrity"],
      "aiComponentTargeted": "framework",
      "llmSpecific": true,
      "classifierConfidence": 0.92
    }
  ],
  "meta": {
    "total": 142,
    "limit": 20,
    "offset": 0
  }
}

GET/api/v1/issues/:id

Get a single issue by its UUID, CVE identifier or GHSA identifier. Returns 404 if not found or not relevant.

Example response

{
  "data": {
    "id": "a1b2c3d4-...",
    "title": "Critical prompt injection in LangChain",
    "summary": "A critical vulnerability was found...",
    "sourceUrl": "https://...",
    "publishedAt": "2026-02-10T12:00:00.000Z",
    "severity": "critical",
    "cvssSeverity": "CRITICAL",
    "cvssScore": "9.8",
    "labels": ["security"],
    "issueType": "vulnerability",
    "cveId": "CVE-2026-1234",
    "cweIds": ["CWE-77"],
    "affectedPackages": ["langchain"],
    "solution": "Upgrade to v0.1.1 or later",
    "attackType": ["prompt_injection"]
  }
}

GET/api/v1/advisories/:id

Look up one record by identifier. The identifier can be a CVE identifier, a GHSA identifier or the record's UUID, and CVE and GHSA identifiers match in any letter case. Returns the same payload as /api/v1/issues/:id, and 404 when no published record carries the identifier.

Example response

// GET /api/v1/advisories/CVE-2026-1234
{
  "data": {
    "id": "a1b2c3d4-...",
    "title": "Critical prompt injection in LangChain",
    "summary": "A critical vulnerability was found...",
    "sourceUrl": "https://...",
    "publishedAt": "2026-02-10T12:00:00.000Z",
    "severity": "critical",
    "cvssSeverity": "CRITICAL",
    "cvssScore": "9.8",
    "labels": ["security"],
    "issueType": "vulnerability",
    "cveId": "CVE-2026-1234",
    "cweIds": ["CWE-77"],
    "affectedPackages": ["langchain"],
    "solution": "Upgrade to v0.1.1 or later",
    "attackType": ["prompt_injection"]
  }
}

GET/api/v1/topics

List the topic catalog with each topic's matching patterns and current counts. Pass a topic's key as the topic parameter of /api/v1/issues to list its items.

Example response

{
  "data": [
    {
      "key": "mcp",
      "label": "Model Context Protocol",
      "group": "technology",
      "description": "The Model Context Protocol and the servers and clients that expose tools and data to models through it.",
      "patterns": ["\\bmodel context protocol\\b", ...],
      "addedOn": "2026-10-09",
      "counts": {
        "total": 310,
        "last90Days": 84,
        "previous90Days": 61,
        "monthly": [{ "month": "2025-05", "n": 4 }, ...]
      }
    }
  ],
  "meta": {
    "catalogVersion": "3f9a1c2b7d4e",
    "matchingRule": "title matches a pattern, or the summary matches patterns at least twice"
  }
}

GET/api/v1/digest/latest

Get the latest daily TLDR digest. Falls back to the most recent non-empty digest.

Example response

{
  "data": {
    "date": "2026-02-12",
    "content": "- **Critical RCE in LangChain Agents:** ...\n- ...",
    "issueCount": 8,
    "generatedAt": "2026-02-12T06:00:00.000Z"
  }
}

POST/api/v1/scan

Look up issues by package name or vendor name. Accepts a list of package names and/or vendor names and returns matching issues plus a severity histogram. Use this instead of chaining multiple filtered /issues calls. Matching is by name, not by version. To check the versions a project pins, use POST /api/v1/check.

Parameters

NameTypeDescription
packagesstring[] (body)Package names to check, e.g. ["langchain", "llama-index"].
vendorsstring[] (body)Vendor names to check, e.g. ["OpenAI", "Anthropic"].
severityMinstring (body)Minimum severity: "critical" | "high" | "medium" | "low" | "info".
sinceISO 8601 date (body)Only include issues published after this date.

Example response

// Request
POST /api/v1/scan
Content-Type: application/json
{
  "packages": ["langchain"],
  "vendors": ["OpenAI"],
  "severityMin": "high"
}

// Response
{
  "data": [
    {
      "id": "a1b2c3d4-...",
      "title": "CVE-2026-1234: Prompt injection in LangChain",
      "severity": "critical",
      "cveId": "CVE-2026-1234",
      "matchedPackages": ["langchain"],
      "matchedVendors": []
    }
  ],
  "meta": {
    "total": 1,
    "bySeverity": { "critical": 1, "high": 0, "medium": 0, "low": 0, "info": 0 }
  }
}

GET/api/v1/issues/stix

Export issues as a STIX 2.1 bundle. Compatible with MISP, OpenCTI, ThreatConnect, and other threat intelligence platforms.

Parameters

NameTypeDescription
severitystringFilter by severity (e.g. "critical", "high")
issueTypestringFilter by issue type (e.g. "vulnerability")
sinceISO 8601 dateOnly return issues published after this date
limitnumberMax issues to include (default 50, max 100)

Example response

{
  "type": "bundle",
  "id": "bundle--a1b2c3d4-...",
  "objects": [
    {
      "type": "identity",
      "spec_version": "2.1",
      "id": "identity--d3c1e7a0-...",
      "name": "AI Sec Watch",
      "identity_class": "system"
    },
    {
      "type": "vulnerability",
      "spec_version": "2.1",
      "id": "vulnerability--a1b2c3d4-...",
      "name": "CVE-2026-1234",
      "description": "Critical prompt injection...",
      "external_references": [
        { "source_name": "cve", "external_id": "CVE-2026-1234" }
      ]
    },
    {
      "type": "attack-pattern",
      "spec_version": "2.1",
      "id": "attack-pattern--e5f6a7b8-...",
      "name": "Prompt Injection"
    }
  ]
}

GET/api/v1/stats

Get aggregate platform statistics.

Example response

{
  "data": {
    "totalIssues": 1420,
    "totalDigests": 85,
    "last24h": 12,
    "last7d": 67
  }
}

POST/api/v1/webhooks

Create a webhook to receive a notification after each fetch cycle in which new issues match your filters. Requires WEBHOOK_API_KEY bearer auth. Payloads are signed with HMAC-SHA256.

Parameters

NameTypeDescription
urlstring (body)The HTTPS URL to receive webhook POSTs
filtersobject (body)Optional filters: { severity, issueType, vendor, llmSpecific }

Example response

// Request
POST /api/v1/webhooks
Authorization: Bearer YOUR_WEBHOOK_API_KEY
{
  "url": "https://your-server.com/webhook",
  "filters": { "severity": "critical", "llmSpecific": true }
}

// Response (201)
{
  "data": {
    "id": "a1b2c3d4-...",
    "url": "https://your-server.com/webhook",
    "secret": "hmac_secret_hex_string",
    "active": true
  }
}

// Webhook payload (POST to your URL)
{
  "event": "new_issues",
  "issues": [ ... ],
  "deliveredAt": "2026-03-12T12:00:00.000Z"
}
// Header: X-Webhook-Signature: sha256=...

Error responses

All errors follow a consistent format:

{
  "error": {
    "message": "Rate limit exceeded. Max 60 requests per minute.",
    "status": 429
  }
}
StatusMeaning
400Bad request (invalid parameters)
404Resource not found
413Request too large (Stack Check accepts up to 6 MB)
429Rate limit exceeded
500Internal server error
502Stack Check could not be completed

How to cite

Cite the dataset when you use it in academic research, industry analysis or threat intelligence work. Copy the citation text, or download it as a file for a reference manager such as Zotero, Mendeley or EndNote.

@misc{luu2026aisecwatch_dataset,
  author       = {Luu, Truong (Jack)},
  title        = {{AI Sec Watch Dataset}: {AI/LLM} Security Threat Intelligence},
  year         = {2026},
  publisher    = {Zenodo},
  doi          = {10.5281/zenodo.19519469},
  url          = {https://doi.org/10.5281/zenodo.19519469},
  note         = {Data set. 48 fields per record, in CSV, JSON and JSONL. Accessed: 2026-10-29}
}