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.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
Shellcurl -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.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
Shellcurl -X POST "https://aisecwatch.com/api/v1/scan" \ -H "Content-Type: application/json" \ -d '{ "packages": ["langchain", "llama-index"], "vendors": ["OpenAI", "Anthropic"], "severityMin": "high" }'3.Call the API
List issues with filters and pagination. Reads need no key and work from any origin. GET /api/v1/issues reference
Shellcurl "https://aisecwatch.com/api/v1/issues?severity=critical&limit=10" \ -H "Accept: application/json"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
| Method | Path | Description |
|---|---|---|
| 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. |
| 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. |
| 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. |
| GET | /api/v1/issues | List relevant, processed security issues with optional filtering and pagination. |
| 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. |
| 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. |
| 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. |
| GET | /api/v1/digest/latest | Get the latest daily TLDR digest. Falls back to the most recent non-empty digest. |
| 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. |
| GET | /api/v1/issues/stix | Export issues as a STIX 2.1 bundle. Compatible with MISP, OpenCTI, ThreatConnect, and other threat intelligence platforms. |
| GET | /api/v1/stats | Get aggregate platform statistics. |
| 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. |
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
| Name | Type | Description |
|---|---|---|
| files | object[] (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. |
| osv | boolean (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. |
| format | string (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
| Name | Type | Description |
|---|---|---|
| q | string | Match part of the package name |
| ecosystem | string | One of "pypi", "npm", "go", "cargo" |
| exposure | string | "direct" (declares an LLM dependency), "transitive" (reaches one through dependencies), "none", or "any" for every tracked package. Default: direct and transitive. |
| sdk | string | Catalog key of an SDK or framework the package declares (e.g. "openai", "langchain", "mcp") |
| authority | string | Authority kind in the package profile: "execution", "filesystem", "shell", "browser", "http", "mcp_tools" |
| sort | string | "integrated" (most recent LLM integration first, the default), "name" or "advisories" |
| page | number | Page number (default 1) |
| perPage | number | Results 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
| Name | Type | Description |
|---|---|---|
| ecosystem | string (path) | One of "pypi", "npm", "go", "cargo" |
| name | string (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
| Name | Type | Description |
|---|---|---|
| search | string | Search issues by title, headline, summary and CVE ID |
| label | string | Filter by label (e.g. "security", "privacy", "research", "safety") |
| severity | string | Filter by severity (e.g. "critical", "high", "medium", "low") |
| issueType | string | Filter by issue type: "vulnerability", "incident", "news", "regulatory", "research" |
| vendor | string | Filter by affected vendor (e.g. "OpenAI", "Anthropic", "Google", "LangChain") |
| package | string | Filter by affected package (e.g. "langchain", "llama-index"). The name is normalized before matching: lower case, with runs of "-", "_" and "." treated alike. |
| topic | string | Filter by topic key from /api/v1/topics (e.g. "mcp", "prompt-injection"). An unknown key returns 400. |
| since | ISO 8601 date | Only return issues published after this date |
| limit | number | Results per page (default 20, max 100) |
| offset | number | Number of results to skip (default 0) |
| confidenceMin | number | Minimum 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
| Name | Type | Description |
|---|---|---|
| packages | string[] (body) | Package names to check, e.g. ["langchain", "llama-index"]. |
| vendors | string[] (body) | Vendor names to check, e.g. ["OpenAI", "Anthropic"]. |
| severityMin | string (body) | Minimum severity: "critical" | "high" | "medium" | "low" | "info". |
| since | ISO 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
| Name | Type | Description |
|---|---|---|
| severity | string | Filter by severity (e.g. "critical", "high") |
| issueType | string | Filter by issue type (e.g. "vulnerability") |
| since | ISO 8601 date | Only return issues published after this date |
| limit | number | Max 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
| Name | Type | Description |
|---|---|---|
| url | string (body) | The HTTPS URL to receive webhook POSTs |
| filters | object (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
}
}| Status | Meaning |
|---|---|
| 400 | Bad request (invalid parameters) |
| 404 | Resource not found |
| 413 | Request too large (Stack Check accepts up to 6 MB) |
| 429 | Rate limit exceeded |
| 500 | Internal server error |
| 502 | Stack 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}
}