An automated pipeline that watches the National Vulnerability Database for newly published CVEs, turns each one into a concise, hunter-focused summary using Gemini, and posts it to X. It is built for a bug bounty and application security audience: every post is written to answer three questions fast: what is the bug, how severe is it, and is it worth a hunter's time.
- Fetch: Queries the NVD REST API for CVEs published within the current resume window, using wall-clock state from the last successful run plus a small safety buffer to account for indexing lag.
- Filter: Skips CVEs already recorded in the append-only processed log. The processed log is a deduplication safety net; it does not drive the resume window.
- Reference: Selects the most useful reference URL from the CVE, prioritizing
Exploit,Third Party Advisory,Vendor Advisory,Patch, andIssue Trackingreferences. The selected URL is used directly without a URL shortener. - Summarize: Sends the CVE details to Gemini with a strict system prompt that produces a fixed-format post: CVE ID, severity/CVSS, bug bounty relevance, a dense vulnerability description, a concrete hunting strategy when relevant, and the reference URL.
- Backup: Saves each generated post as
cve-<ID>.txtbefore publishing. Existing valid backups can be reused instead of calling Gemini again. - Post: Hands the generated text to a Selenium-driven browser session that publishes it to X using the configured cookie session.
- Log: Only after a successful X post does the CVE get appended to the processed log. Failed posts remain unresolved and are picked up again on a future run.
The script processes CVEs one at a time, oldest first, with a per-run processing limit. It is designed to be safe to run repeatedly, including on a schedule via cron, systemd timer, or another scheduler.
Bug bounty hunters and security researchers need to know about new, testable vulnerabilities quickly, but raw NVD entries are verbose and rarely say what actually matters for hunting: is this remotely exploitable, is it worth testing on a live scope, and where exactly does the bug live. This project automates that triage and distribution step, turning a firehose of CVE metadata into a small number of scannable, actionable posts.
NVD API ----> cve-alert.py ----> Gemini API
| |
| v
| cve-backups/*.txt
| |
| v
+------------> post_to_x.py
|
v
X (Selenium)
|
+---------------+---------------+
| |
v v
processed_cves.jsonl last_run_state.json
(deduplication) (resume state)
| File | Purpose |
|---|---|
cve-alert.py |
Main pipeline: fetches CVEs from NVD, extracts fields, selects a reference URL, calls Gemini, saves a backup post, and hands it off to post_to_x.py. |
post_to_x.py |
Standalone poster. Reads a text file and publishes it to X using Selenium, supporting interactive login or an imported cookie session. |
- Python 3.10 or later
requestsselenium- Chrome or Chromium installed
persistent-chrome-session: a separate library thatpost_to_x.pyimports for persistent browser/profile handling.- A Google Gemini API key
- An X (Twitter) account
- An exported X session cookie for the automated/headless pipeline, or a display-enabled environment for standalone interactive login
post_to_x.py also imports create_driver_from_cookies, which is used by the --cookies-file flow. This function is not part of the currently published persistent-chrome-session module and will need to be available in the local persistent_chrome_session.py implementation used with this project.
There is no requirements.txt in the repository at this time; install the Python dependencies manually, for example:
pip install requests seleniumCredentials are loaded from token files first, with environment variables used as fallbacks. Token files may contain one credential per line; blank lines and lines beginning with # are ignored.
| Token file | Environment variable fallback | Purpose |
|---|---|---|
gemini.token |
GEMINI_API_KEY |
One or more Gemini API keys, tried in order when a request fails. |
The NVD API key is supplied through an environment variable:
| Variable | Default | Description |
|---|---|---|
NVD_API_KEY |
unset | Optional NVD API key. When present, the default NVD request delay is reduced. |
Behavior can be further tuned with these environment variables:
| Variable | Default | Description |
|---|---|---|
BACKUP_DIR |
./cve-backups |
Where generated cve-<ID>.txt post files are saved. |
PROCESSED_LOG |
./processed_cves.jsonl |
Append-only log used for CVE deduplication. |
STATE_FILE |
./last_run_state.json |
Stores the wall-clock end time of the last successful run. |
GEMINI_MODEL |
gemini-3.6-flash |
Gemini model used for summarization. |
NVD_PAGE_SIZE |
200 |
Number of CVEs requested per NVD API page. |
NVD_REQUEST_DELAY |
0.7 with API key / 6.5 without |
Delay between NVD pagination requests. |
MAX_CVES_PER_RUN |
15 |
Maximum number of CVEs processed during one run. |
FETCH_WINDOW_HOURS |
24 |
Maximum size of the NVD fetch window per run. |
RESUME_SAFETY_MINUTES |
10 |
Small safety buffer applied before the last successful run time. |
INITIAL_LOOKBACK_HOURS |
1 |
Initial look-back used when no previous run state exists. |
EXPECTED_RUN_INTERVAL_MINUTES |
60 |
Expected schedule interval used for informational gap warnings. |
SAFETY_MARGIN_CHARS |
8 |
Extra character margin used to reduce the chance of X rejecting a generated post. |
POST_TO_X_SCRIPT |
alongside cve-alert.py |
Path to post_to_x.py. |
X_COOKIES_FILE |
x.cookies |
Cookie file passed to post_to_x.py. |
GEMINI_TOKENS_FILE |
gemini.token |
Path to the Gemini token file. |
DRY_RUN |
0 |
Set to 1 to generate and save posts locally without publishing to X. |
The pipeline uses last_run_state.json to remember the wall-clock time at which the previous run completed successfully.
This is intentionally separate from processed_cves.jsonl:
last_run_state.jsondrives the time window fetched from NVD.processed_cves.jsonlprevents already-posted CVEs from being processed again.- A small
RESUME_SAFETY_MINUTESbuffer helps cover NVD indexing delays and clock skew. - If the script has been offline for longer than the expected interval, the missed window is automatically caught up, subject to
FETCH_WINDOW_HOURS. - If NVD or Gemini fails hard, the run state is not advanced, allowing the same window to be retried.
- If an individual X post fails, that CVE remains unresolved so a later run can retry it.
post_to_x.py supports two login modes:
- Interactive: opens a visible Chrome window for a normal login. Requires a display (
DISPLAY/WAYLAND_DISPLAY) and is not suitable for a plain headless SSH session. - Cookie import: for headless servers. Export the
Cookieheader from an already-authenticated X browser session, save it as a single line in a local file, and pass it with--cookies-file. The session should contain the authentication cookies required by X, includingauth_tokenandct0.
Treat the cookie file like a password: restrict its permissions, keep it out of version control, and never paste its contents into a shared terminal or chat.
Run the main pipeline directly, or on a schedule:
python cve-alert.pyReset the saved resume state and processed log while keeping timestamped backups:
python cve-alert.py --resetRun the poster on its own against a pre-written text file using an existing cookie session:
python post_to_x.py post.txt --cookies-file x.cookiesRun the standalone poster with an interactive X login:
python post_to_x.py post.txtGenerate and save posts without publishing anything:
DRY_RUN=1 python cve-alert.pyEach generated post follows a fixed structure so it can be scanned at a glance:
🚨 CVE-YYYY-NNNNN
📊 Severity: SEVERITY (CVSS X.X)
🎯 BBP Relevance: HIGH/MEDIUM/LOW/NONE
[Dense, technically specific vulnerability description]
🔎 [Concrete, vulnerability-specific hunting strategy]
[Reference URL]
The Gemini prompt targets 250–270 characters for the complete post, including line breaks. The pipeline uses X-weighted character counting, treats URLs as a fixed 23-character weight, and applies an additional safety margin before accepting generated output.
The reference URL is used in full and is not shortened. No hashtags are added.
For CVEs that are clearly not relevant to web or bug bounty testing, the hunting-strategy line may be omitted and the relevance can be marked NONE.
The pipeline is designed so that failures at any stage do not silently advance the resume point past unresolved work:
- A CVE is only marked as processed after it has actually been posted successfully.
- Hard NVD/Gemini failures leave the previous run state untouched, allowing the window to be retried.
- Failed X posts remain unresolved and are pulled back into a future run.
- Existing valid
cve-<ID>.txtbackups can be reused instead of generating the same Gemini response again. - CVEs are processed oldest first.
MAX_CVES_PER_RUNlimits how much work is performed in one execution; remaining candidates are picked up by subsequent runs.FETCH_WINDOW_HOURSprevents a large outage from creating an unbounded single-run catch-up window.
No license file is currently included in this repository. Until one is added, all rights are reserved by the author, and reuse should not be assumed.
This tool is intended to support legitimate security research, bug bounty triage, and vulnerability awareness. Users are responsible for complying with the terms of service of the NVD API, Google Gemini, and X, and with any applicable laws in their jurisdiction.
