Skip to content

matankriel/echo-language-prototype

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Echo — CVE Remediation Demo

A focused prototype that shows one core concept: when a developer requests a vulnerable Python package, Echo detects the CVE, shows a detailed remediation block, and either blocks (High) or warns and proceeds (Medium). A separate step demonstrates applying Echo-patched wheels and proving the registry check passes.

What the demo shows

Two distinct severity flows using urllib3 and requests:

Package CVE Severity CVSS Behaviour
urllib3==1.26.0 CVE-2021-33503 High 7.5 CVE info block printed, build blocked (exit 1)
requests==2.28.0 CVE-2023-32681 Medium 6.1 CVE info block printed, proceeds with vulnerable version

Both severity levels show the same informational block:

[ECHO] ⚠ CVE DETECTED: {pkg}=={ver} — {cve_id} ({severity}, CVSS {cvss})
       Affected range:   {range}
       Safe release:     {pkg}>={first_patched}
       Echo patched:     {pkg}=={pivot}+echo1  ← same version, backport fix applied
       Fix options:
         pip install '{pkg}>={first_patched}'        # upgrade to safe release
         pip install '{pkg}=={pivot}+echo1' \
           --find-links factory/artifacts/           # use Echo patched build

Each patched wheel embeds a CycloneDX 1.4 SBOM so security scanners can verify the fix.


Architecture

client/install.py          # pip wrapper: checks registry → shows CVE block → warns/blocks
       │
       ▼
registry/server.py         # FastAPI: PEP 503 simple index + /check endpoint
       │
       ├── GET /check/{package}/{version}   → CVE lookup (early-return for +echo1 versions)
       ├── GET /simple/{package}/           → PEP 503 wheel index w/ CVE metadata
       └── GET /files/{filename}            → serve patched wheel

factory/builder.py         # demand-driven backport builder (30-day filter)
factory/sbom.py            # CycloneDX SBOM generator + wheel injector

db/schema.py               # SQLite schema (cves, version_groups, request_log)
db/discover.py             # GHSA discovery: fetches live CVE data → populates DB
db/seed.py                 # seeds demo request_log rows (30-day window illustration)

Demand-driven build filter

The builder only builds a wheel if a matching package version was requested within the last 30 days (tracked in request_log). Seeded demo data illustrates both sides:

Package Version Last Requested Outcome
requests 2.28.0 7 days ago BUILD (within window, in CVE range)
requests 2.26.0 50 days ago SKIP (outside 30-day window)
urllib3 1.26.0 15 days ago pre-built (skip)

+echo1 registry early-return

/check/{package}/{version} immediately returns {"vulnerable": false} when the version string contains +echo1. This ensures that once you install an Echo-patched wheel and re-run with the patched spec, the check passes without hitting the CVE database.


Getting a GitHub token

Echo uses the GitHub Security Advisory (GHSA) GraphQL API to fetch live CVE data. The API requires a GitHub personal access token — no special scopes or permissions are needed, just a basic token that proves you have a GitHub account.

Classic token (simplest):

  1. Go to github.com → Settings → Developer settings → Personal access tokens → Tokens (classic)
  2. Click Generate new token (classic)
  3. Give it any name (e.g. echo-demo)
  4. Leave all scopes unchecked — the GHSA API only needs public read access
  5. Click Generate token and copy it

Fine-grained token (alternative):

  1. Go to github.com → Settings → Developer settings → Personal access tokens → Fine-grained tokens
  2. Click Generate new token
  3. Set expiration, leave repository access as Public Repositories (read-only)
  4. No additional permissions needed — click Generate token and copy it

Once you have a token:

export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx

Tokens starting with ghp_ are classic tokens; github_pat_ are fine-grained. Both work.


Quick start

# 1. Export your GitHub token (see above)
export GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx

# 2. Reset to clean state (creates venvs, plants vulnerable versions)
./reset.sh

# 3. Run the full 8-step demo
./run.sh

Requirements: Python 3.9+, internet access, GITHUB_TOKEN env var. Both scripts auto-create .venv (tool environment) and .demo_env (simulated customer environment).

Manual steps

# Discover CVEs from GHSA and populate the database
export GITHUB_TOKEN=ghp_xxx
python3 db/discover.py urllib3 requests

# Seed demo request_log rows (30-day demand window illustration)
python3 db/seed.py

# Start registry on :8000
uvicorn registry.server:app --port 8000

# Run builder (builds requests wheel, skips pre-built urllib3 wheels)
python3 factory/builder.py

# Medium severity: CVE info block + proceeds with vulnerable version
python3 client/install.py requests==2.28.0

# High severity: CVE info block + build blocked (exit 1)
python3 client/install.py urllib3==1.26.0

# Full requirements (blocked due to urllib3 High CVE)
python3 client/install.py -r client/requirements.txt

# Install Echo-patched wheels
pip install "urllib3==1.26.4+echo1" "requests==2.28.2+echo1" \
  --find-links factory/artifacts/

# Re-run with patched specs — registry returns vulnerable=false → succeeds
python3 client/install.py "urllib3==1.26.4+echo1" "requests==2.28.2+echo1"

Demo walkthrough

Step 1 — Pre-flight

Checks Python, dependencies, and verifies the three urllib3 pre-built wheels exist in factory/artifacts/. Shows the demo environment's "before" state (urllib3==1.26.0, requests==2.28.0).

Step 2 — Discover CVEs + seed DB + start registry

Runs db/discover.py to query the GitHub Security Advisory database (GHSA) for urllib3 and requests advisories; maps each advisory to a cves + version_groups row and resolves the pivot version from PyPI. Then runs db/seed.py to insert 5 synthetic request_log rows. Starts the FastAPI registry on :8000.

Step 3 — Builder (demand-driven)

Runs factory/builder.py. urllib3 groups are already built (skipped). The requests group (2.28.0 was requested 7 days ago) is eligible and built. A CycloneDX SBOM is injected into the wheel.

Step 4 — Medium severity (requests)

[ECHO] ⚠ CVE DETECTED: requests==2.28.0 — CVE-2023-32681 (Medium, CVSS 6.1)
       Affected range:   >=2.1.0,<2.31.0
       Safe release:     requests>=2.31.0
       Echo patched:     requests==2.28.2+echo1  ← same version, backport fix applied
       Fix options:
         pip install 'requests>=2.31.0'
         pip install 'requests==2.28.2+echo1' --find-links factory/artifacts/

[ECHO] ⚠ Proceeding with vulnerable version (Medium severity — explicit fix recommended)

requests==2.28.0 is installed in the demo environment (not the patched version — the developer must apply the fix explicitly).

Step 5 — High severity (urllib3 + requests)

[ECHO] ⚠ CVE DETECTED: urllib3==1.26.0 — CVE-2021-33503 (High, CVSS 7.5)
       ...
[ECHO] ⚠ CVE DETECTED: requests==2.28.0 — CVE-2023-32681 (Medium, CVSS 6.1)
       ...
[ECHO] ✗ BUILD BLOCKED — one or more High severity CVEs require explicit upgrade.

client/install.py exits with code 1. The build is aborted due to the urllib3 High CVE.

Step 6 — Apply Echo patches

Installs urllib3==1.26.4+echo1 and requests==2.28.2+echo1 directly into the demo environment using --find-links factory/artifacts/. Shows the installed versions to confirm the patched wheels are active.

Step 7 — Re-run install with patched specs

Runs install.py with the +echo1 version specs directly. The registry /check endpoint sees +echo1 in the version string and returns {"vulnerable": false} immediately — no CVE block, no blocking, clean exit 0.

Registry check: GET /check/urllib3/1.26.4+echo1 → {"vulnerable": false}

Step 8 — Registry inspection

Shows the PEP 503 index for urllib3 (with embedded CVE metadata in HTML comments) and the updated request_log counts.


CVE database

CVE-2021-33503 — urllib3, High, CVSS 7.5 ReDoS via crafted HTTP response header in urllib3.util.url. Fixed in 1.26.5.

Version range Pivot Artifact
>=1.25.4,<1.25.8 1.25.7 urllib3-1.25.7+echo1-py2.py3-none-any.whl
>=1.25.8,<1.26.5 1.26.4 urllib3-1.26.4+echo1-py2.py3-none-any.whl
>=2.0.0,<2.0.6 2.0.5 urllib3-2.0.5+echo1-py3-none-any.whl

CVE-2023-32681 — requests, Medium, CVSS 6.1 SSRF via trusted Host header forwarded through redirects to untrusted origins. Fixed in 2.31.0.

Version range Pivot Artifact
>=2.1.0,<2.31.0 2.28.2 requests-2.28.2+echo1-py3-none-any.whl (built during demo)

SBOM verification

python3 -c "
import zipfile, json
with zipfile.ZipFile('factory/artifacts/requests-2.28.2+echo1-py3-none-any.whl') as zf:
    sbom_path = next(n for n in zf.namelist() if 'sbom.cdx.json' in n)
    print(json.dumps(json.loads(zf.read(sbom_path)), indent=2))
"
# Expected: CycloneDX SBOM with CVE-2023-32681, analysis.state = "resolved"

File structure

echo/
├── db/
│   ├── schema.py          # SQLite schema + get_connection() + init_db()
│   ├── discover.py        # GHSA discovery service → populates cves + version_groups
│   └── seed.py            # seeds demo request_log rows
├── factory/
│   ├── builder.py         # demand-driven backport wheel builder
│   ├── sbom.py            # CycloneDX SBOM generator + wheel injector
│   └── artifacts/         # pre-built urllib3 wheels + CVE patches
├── registry/
│   └── server.py          # FastAPI PEP 503 registry + /check endpoint
├── client/
│   ├── install.py         # pip wrapper with CVE check + remediation output
│   └── requirements.txt   # urllib3==1.26.0 + requests==2.28.0 (demo "before")
├── run.sh                 # 8-step demo script
└── reset.sh               # reset to clean state

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors