Preserve public PoCs with resumable Wayback captures

This commit is contained in:
0xMarcio committed 2026-10-22 19:07:57 +02:00
1 parent 03db7ffa99
commit 5480e9df70
29 files changed
+18454 -15780

No files matched your search

+336
View File
@@ -0,0 +1,336 @@
from __future__ import annotations
import copy
import gzip
import io
import json
import sys
import tempfile
import unittest
from datetime import datetime, timezone
from pathlib import Path
from unittest.mock import MagicMock, patch
from urllib.error import HTTPError
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / 'scripts'))
import archive_pocs as archive
import build_site
import releases
URL = 'https://github.com/owner/poc'
CVE = 'CVE-2026-1234'
def snapshot(url=URL, stamp=None):
stamp = stamp or datetime.now(timezone.utc).strftime('%Y%m%d%H%M%S')
return {'url': archive.snapshot_url(url, stamp), 'timestamp': stamp, 'verified_at': archive.now()}
class ArchiveTests(unittest.TestCase):
def setUp(self):
self.target = {'original': URL, 'cves': [CVE], 'priority': archive.now()}
self.rows = {}
self.client = MagicMock()
self.client.lookup.return_value = None
self.client.submit.return_value = {'job_id': 'pending-123'}
p = patch.object(archive.link_health, 'unavailable', return_value=False)
self.dead = p.start()
self.addCleanup(p.stop)
def test_inventory_limits_cve_year_and_preserves_source_paths(self):
ledger = {
'old': {'url': URL + '-old', 'cve': 'CVE-2025-1234'},
'new': {'url': URL, 'cve': CVE, 'head': 'b' * 40, 'sha': 'a' * 40,
'commit_verified': True, 'paths': ['wrong.py'], 'history_paths': ['PoC x.py']},
'future': {'url': URL, 'cve': 'CVE-2027-4567'},
'bad': {'url': URL + '-blocked', 'cve': CVE},
'excluded': {'url': URL + '-excluded', 'cve': CVE},
'withdrawn': {'url': URL + '-withdrawn', 'cve': CVE, 'gone': '2026-01-01'},
}
with patch.object(releases, 'load_ledger', return_value=ledger), \
patch.object(build_site, 'load_blacklist', return_value={'owner/poc-blocked'}), \
patch.object(build_site, 'load_source_exclusions', return_value={(CVE, 'owner/poc-excluded')}):
result = archive.inventory()
self.assertEqual(len(result), 2)
self.assertEqual(set(result[URL]['cves']), {CVE, 'CVE-2027-4567'})
raw = next(v for v in result.values() if v.get('parent'))
self.assertTrue(raw['original'].endswith('/' + 'a' * 40 + '/PoC%20x.py'))
def test_snapshot_validation_rejects_fake_hosts_invalid_dates_and_private_urls(self):
good = snapshot()
self.assertTrue(archive.valid_snapshot({'snapshot': good}))
for url in ('http://localhost/a', 'http://127.0.0.1/a', 'http://169.254.169.254/a',
'https://user:[email protected]/a', 'javascript:alert(1)', 'https://host.internal/a'):
self.assertFalse(archive.public_url(url), url)
for bad in ({**good, 'url': good['url'].replace('web.archive.org', 'web.archive.org.evil.example')},
{**good, 'timestamp': '20260231000000'}, {**good, 'verified_at': ''}):
self.assertFalse(archive.valid_snapshot({'snapshot': bad}))
def test_first_observation_does_not_disqualify_older_public_captures(self):
ledger = [{'url': URL, 'cve': CVE, 'seen': '2026-10-21T12:00:00Z'},
{'url': URL + '-dated', 'cve': CVE, 'seen': '2026-10-21T12:00:00Z',
'source': '2026-05-13'}]
with patch.object(archive, 'eligible_ledger', return_value=ledger):
result = archive.inventory()
self.assertNotIn('not_before', result[URL])
self.assertEqual(result[URL + '-dated']['not_before'], '2026-05-13T00:00:00Z')
def test_pinned_file_urls_preserve_bytes_without_additional_github_queries(self):
parent = URL + '/blob/' + 'b' * 40 + '/path/PoC%20file.py#example'
with patch.object(archive, 'eligible_ledger', return_value=[{'url': parent, 'cve': CVE}]):
result = archive.inventory()
raw = 'https://raw.githubusercontent.com/owner/poc/' + 'b' * 40 + '/path/PoC%20file.py'
self.assertEqual(result[raw]['parent'], archive.identity(parent))
self.assertEqual(result[raw]['parent_original'], parent)
def test_lookup_rejects_capture_of_a_different_url(self):
client = archive.Client()
snap = snapshot(URL + '-other')
response = {'archived_snapshots': {'closest': {**snap, 'status': '200', 'available': True}}}
with patch.object(client, 'json', return_value=response):
self.assertIsNone(client.lookup(URL))
def test_existing_capture_is_verified_without_resubmission(self):
self.client.lookup.return_value = snapshot()
with patch.object(archive, 'verify_snapshot', return_value=True):
archive.process(URL, self.target, self.rows, self.client, capture=False)
self.assertTrue(archive.valid_snapshot(self.rows[URL]))
self.client.submit.assert_not_called()
def test_pending_job_is_checkpointed_and_polled_without_duplicate_submission(self):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.assertEqual(self.rows[URL]['job_id'], 'pending-123')
self.client.status.return_value = {'status': 'pending'}
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.client.submit.assert_called_once()
self.client.lookup.assert_not_called()
self.assertEqual(self.rows[URL]['attempts'], 1)
def test_success_requires_replay_verification(self):
archive.process(URL, self.target, self.rows, self.client, capture=True)
snap = snapshot()
self.client.status.return_value = {'status': 'success', 'timestamp': snap['timestamp'], 'original_url': URL}
with patch.object(archive, 'verify_snapshot', return_value=True):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.assertEqual(self.rows[URL]['status'], 'available')
self.assertNotIn('job_id', self.rows[URL])
self.assertEqual(archive.published_snapshots(self.rows)[URL]['url'], snap['url'])
def test_expired_job_recovers_by_lookup(self):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.client.status.side_effect = archive.ArchiveError('http-404')
self.client.lookup.return_value = snapshot()
with patch.object(archive, 'verify_snapshot', return_value=True):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.assertNotIn('job_id', self.rows[URL])
self.client.submit.assert_called_once()
def test_refresh_error_keeps_previous_good_capture(self):
old = snapshot(stamp='20260101000000')
self.rows[URL] = {**self.target, 'snapshot': old, 'job_id': 'pending-123', 'attempts': 1}
self.client.status.return_value = {'status': 'error', 'status_ext': 'error:read-timeout'}
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.assertEqual(self.rows[URL]['snapshot'], old)
self.assertEqual(archive.published_snapshots(self.rows)[URL]['url'], old['url'])
def test_unverified_terminal_job_never_resubmits_in_a_loop(self):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.client.status.return_value = {'status': 'success', 'timestamp': snapshot()['timestamp'], 'original_url': URL}
with patch.object(archive, 'verify_snapshot', return_value=False):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.client.submit.assert_called_once()
self.assertNotIn('job_id', self.rows[URL])
self.assertNotIn('candidate', self.rows[URL])
self.assertGreater(self.rows[URL]['next_check_at'], archive.now())
self.assertFalse(archive.valid_snapshot(self.rows[URL]))
def test_transient_replay_failure_retains_candidate_without_resubmission(self):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.client.status.return_value = {'status': 'success', 'timestamp': snapshot()['timestamp'], 'original_url': URL}
with patch.object(archive, 'verify_snapshot', side_effect=archive.ArchiveError('replay-http-404')):
with self.assertRaises(archive.ArchiveError):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.assertIn('candidate', self.rows[URL])
self.assertNotIn('job_id', self.rows[URL])
with patch.object(archive, 'verify_snapshot', return_value=True):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.client.submit.assert_called_once()
self.assertTrue(archive.valid_snapshot(self.rows[URL]))
def test_expired_jobs_do_not_reserve_a_capture_slot(self):
self.rows[URL] = {**self.target, 'job_id': 'old-job', 'submitted_at': archive.after(-7200)}
self.assertFalse(archive.active_job(self.rows[URL]))
archive.process(URL, self.target, self.rows, self.client, capture=False)
self.client.status.assert_not_called()
self.client.lookup.assert_called_once_with(URL)
self.assertNotIn('job_id', self.rows[URL])
def test_dead_original_with_good_capture_clears_stale_work(self):
self.rows[URL] = {**self.target, 'snapshot': snapshot(), 'job_id': 'stale',
'candidate': snapshot(), 'submitted_at': archive.after(-7200)}
self.dead.return_value = True
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.assertNotIn('job_id', self.rows[URL])
self.assertNotIn('candidate', self.rows[URL])
self.assertEqual(self.rows[URL]['status'], 'available')
def test_fragments_never_enter_capture_identity_or_poison_a_shard(self):
original = URL + '#poc'
target = {**self.target, 'original': original}
self.rows[URL] = {**target, 'job_id': 'job', 'submitted_at': archive.now()}
self.client.status.return_value = {'status': 'success', 'timestamp': snapshot()['timestamp'], 'original_url': original}
with patch.object(archive, 'verify_snapshot', return_value=True):
archive.process(URL, target, self.rows, self.client, capture=True)
self.assertNotIn('#', self.rows[URL]['snapshot']['url'])
self.assertTrue(archive.valid_snapshot(self.rows[URL]))
with tempfile.TemporaryDirectory() as directory:
archive.save_records(self.rows, {URL}, Path(directory))
self.assertEqual(archive.load_records(Path(directory)), self.rows)
def test_repeated_unverifiable_capture_gets_increasing_backoff(self):
self.rows[URL] = {**self.target, 'attempts': 7, 'candidate': snapshot()}
with patch.object(archive, 'verify_snapshot', return_value=False):
archive.process(URL, self.target, self.rows, self.client, capture=False)
self.assertGreater(self.rows[URL]['next_check_at'], archive.after(6 * 3600))
def test_redirect_homepage_and_capture_predating_poc_are_not_published(self):
for target, captured in ((self.target, snapshot('https://github.com/')),
({**self.target, 'not_before': archive.now()}, snapshot(stamp='20260101000000'))):
rows = {URL: {**target, 'candidate': captured}}
with patch.object(archive, 'verify_snapshot') as replay:
archive.process(URL, target, rows, self.client, capture=False)
replay.assert_not_called()
self.assertFalse(archive.valid_snapshot(rows[URL]))
def test_account_errors_are_separate_from_target_errors(self):
self.assertEqual(archive.service_error('error:max-daily-bandwidth').cooldown, 86400)
for reason in ('error:filesize-limit', 'error:bandwidth-limit-exceeded',
'error:too-many-daily-captures', 'error:soft-time-limit-exceeded'):
self.assertIsNone(archive.service_error(reason), reason)
def test_daily_submission_budget_is_durable_and_first_capture_is_retained(self):
self.rows[URL] = {**self.target, 'submissions': {'date': archive.now()[:10], 'count': 2}}
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.client.submit.assert_not_called()
old = snapshot(stamp='20260101000000')
self.rows[URL].update(snapshot=old, candidate=snapshot())
with patch.object(archive, 'verify_snapshot', return_value=True):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.assertEqual(self.rows[URL]['snapshot'], old)
def test_source_snapshots_are_attached_to_their_published_parent(self):
raw = 'https://raw.githubusercontent.com/owner/poc/' + 'a' * 40 + '/PoC.py'
rows = {raw: {'original': raw, 'parent': URL, 'snapshot': snapshot(raw)}}
result = archive.published_snapshots(rows, {URL})
self.assertEqual(result[URL]['files'][0]['original'], raw)
self.assertEqual(archive.published_snapshots(rows, set()), {})
def test_source_file_can_recover_a_dead_parent_without_a_page_capture(self):
raw = 'https://raw.githubusercontent.com/owner/poc/' + 'a' * 40 + '/PoC.py'
rows = {raw: {'original': raw, 'parent': URL, 'cves': [CVE], 'snapshot': snapshot(raw)}}
self.dead.return_value = True
with patch.object(archive, 'eligible_ledger', return_value=[{'cve': CVE, 'url': URL, 'field': 'nuclei'}]):
self.assertEqual(archive.archived_fallbacks(rows)[CVE], [('nuclei', rows[raw]['snapshot']['url'])])
def test_recovered_original_keeps_archive_until_it_is_reimported(self):
self.dead.return_value = False
self.rows[URL] = {**self.target, 'snapshot': snapshot()}
with patch.object(archive, 'eligible_ledger', return_value=[{'cve': CVE, 'url': URL, 'gone_reason': 'unavailable'}]):
self.assertEqual(len(archive.archived_fallbacks(self.rows)[CVE]), 1)
def test_managed_fallback_does_not_redate_or_remove_legacy_archive_links(self):
managed = snapshot()['url']
legacy = archive.snapshot_url(URL + '-legacy', '20200101000000')
with patch.object(archive, 'load_records', return_value={URL: {**self.target, 'snapshot': snapshot()}}):
self.assertEqual(releases.published_pairs([{'cve': CVE, 'poc': [managed, legacy]}]), [(CVE, legacy)])
old = releases.record({}, CVE, URL, observed_at='2026-01-01T00:00:00Z')
self.dead.return_value = True
ledger = releases.reconcile({releases.key(CVE, URL): old}, [], observed_at='2026-02-01T00:00:00Z')
row = ledger[releases.key(CVE, URL)]
self.assertEqual(row['seen'], '2026-01-01T00:00:00Z')
self.assertEqual(row['gone_reason'], 'unavailable')
def test_dead_original_is_only_looked_up_and_blacklist_cannot_be_bypassed(self):
self.dead.return_value = True
self.client.lookup.return_value = snapshot()
with patch.object(archive, 'verify_snapshot', return_value=True):
archive.process(URL, self.target, self.rows, self.client, capture=True)
self.client.submit.assert_not_called()
with patch.object(archive, 'eligible_ledger', return_value=[{'cve': CVE, 'url': URL}]):
self.assertEqual(len(archive.archived_fallbacks(self.rows)[CVE]), 1)
self.assertFalse(archive.archived_fallbacks(self.rows, blacklist={'owner/poc'}))
self.assertFalse(archive.archived_fallbacks(self.rows, exclusions={(CVE, 'owner/poc')}))
self.rows[URL]['parent'] = URL + '-parent'
self.assertFalse(archive.archived_fallbacks(self.rows))
def test_cooldown_and_checkpoints_survive_merge(self):
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
source, destination = root / 'incoming', root / 'current'
incoming = {URL: {**self.target, 'checked_at': archive.now(), 'status': 'retry'}}
existing = {URL: {**self.target, 'checked_at': '2026-01-01', 'snapshot': snapshot()}}
archive.save_records(incoming, {URL}, source)
archive.save_records(existing, {URL}, destination)
control = {'retry_after': archive.after(300), 'reason': 'http-429'}
(source / 'control.json').write_text(json.dumps(control))
with patch.object(sys, 'argv', ['archive', '--directory', str(destination), '--merge-from', str(source)]):
self.assertEqual(archive.main(), 0)
self.assertTrue(archive.valid_snapshot(archive.load_records(destination)[URL]))
self.assertEqual(json.loads((destination / 'control.json').read_text()), control)
def test_quota_and_retry_after_are_respected(self):
client = archive.Client('dummy', 'dummy')
with patch.object(client, 'json', return_value={'daily_captures': 30000, 'daily_captures_limit': 30000, 'available': 3}):
with self.assertRaises(archive.ArchiveError) as result:
client.capacity()
self.assertEqual(result.exception.cooldown, 86400)
self.assertEqual(archive.retry_delay('1200'), 1200)
self.assertGreaterEqual(archive.retry_delay('invalid'), 300)
opener = MagicMock()
opener.open.side_effect = HTTPError('https://web.archive.org/save', 429, 'wait', {'Retry-After': '600'}, None)
with patch.object(archive.request, 'build_opener', return_value=opener):
with self.assertRaises(archive.ArchiveError) as result:
client.submit(URL)
self.assertEqual(result.exception.cooldown, 600)
def test_capture_uses_only_explicit_url_and_never_archives_errors(self):
client = archive.Client('dummy', 'dummy')
with patch.object(client, 'json', return_value={'job_id': '1'}) as send:
client.submit(URL)
payload = send.call_args.args[1]
self.assertEqual(payload['capture_all'], '0')
self.assertEqual(payload['capture_outlinks'], '0')
self.assertEqual(payload['if_not_archived_within'], '30d')
def test_replay_rejects_login_shells_errors_and_external_redirects(self):
snap = snapshot()
response = MagicMock()
response.__enter__.return_value = response
response.status = 200
response.url = snap['url'].replace(snap['timestamp'] + '/', snap['timestamp'] + 'id_/')
response.headers = {'Content-Type': 'text/html'}
opener = MagicMock()
opener.open.return_value = response
with patch.object(archive.request, 'build_opener', return_value=opener):
for body in (b'', b'<title>404 Not Found</title>', b'<title>Sign in to GitHub</title>'):
response.read.return_value = body
self.assertFalse(archive.verify_snapshot(copy.deepcopy(snap), URL))
response.read.return_value = b'<title>PoC for CVE-2026-4044</title><article>research</article>'
self.assertTrue(archive.verify_snapshot(snap, URL))
self.assertFalse(archive.verify_snapshot(snap, 'https://hackerone.com/reports/1234'))
redirect = archive.ReplayRedirect()
self.assertIsNone(redirect.redirect_request(None, None, 302, '', {}, 'http://127.0.0.1/private'))
self.assertIsNone(archive.NoRedirect().redirect_request(None, None, 302, '', {}, 'https://archive.org/'))
def test_gzip_replay_is_decoded_before_content_and_hash_validation(self):
response = io.BytesIO(gzip.compress(b'<title>Sign in to GitHub</title>'))
response.headers = {'Content-Encoding': 'gzip'}
self.assertEqual(archive.response_bytes(response, 1000), b'<title>Sign in to GitHub</title>')
response = io.BytesIO(gzip.compress(b'x' * 1001))
response.headers = {'Content-Encoding': 'gzip'}
with self.assertRaisesRegex(archive.ArchiveError, 'too-large'):
archive.response_bytes(response, 1000)
if __name__ == '__main__':
unittest.main()
+3 -2
View File
@@ -87,10 +87,11 @@ process.stdout.write(JSON.stringify(markup));
def page_blocks(entry: dict) -> dict[str, list[tuple[str, str, str]]]:
"""(href, label, note) for each row under each counted heading of a CVE page."""
"""(href, label, note) for each row under each counted heading of a CVE page,
read without the Wayback control each PoC row ends with."""
data = {"cves": [entry], "meta": {}, "epss": {}, "kev": {}, "nuclei": {}, "repo_meta": REPO_META,
"related": {}, "lastmod": {entry["cve"]: "2026-10-07"}}
markup = build_pages.page(entry, data)
markup = re.sub(r'(?: · )?<(a|span) class="wayback[^"]*"[^>]*>[^<]*</\1>', "", build_pages.page(entry, data))
return {
heading: [tuple(html.unescape(part) for part in row) for row in re.findall(
r'<li><a href="([^"]*)"[^>]*>([^<]*)</a>(?:<span>([^<]*)</span>)?</li>', body)]
+356
View File
@@ -3,6 +3,7 @@ from __future__ import annotations
import copy
import io
import json
import re
import sys
import tempfile
import unittest
@@ -16,6 +17,17 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "scripts"))
import build_pages
import build_seo
# A source file saved at a pinned commit, as archives.json lists it under its page.
COMMIT = "0123456789abcdef0123456789abcdef01234567"
def raw_file(path: str, repository: str = "owner/poc", commit: str = COMMIT) -> str:
return f"https://raw.githubusercontent.com/{repository}/{commit}/{path}"
def saved_file(original: str, stamp: str = "20261022161013") -> dict:
return {"original": original, "url": f"https://web.archive.org/web/{stamp}/{original}", "timestamp": stamp}
class ContentDateTests(unittest.TestCase):
def setUp(self) -> None:
@@ -70,6 +82,65 @@ class ContentDateTests(unittest.TestCase):
changed = {**self.entry, "desc": "Widget flaw, now remote"}
self.assertEqual(build_pages.content_state(changed, self.data, published)[1], self.data["today"])
def test_confirmed_snapshots_advance_the_date_and_other_archive_records_do_not(self) -> None:
url, stamp = self.entry["poc"][0], "20251021093000"
record = {"url": f"https://web.archive.org/web/{stamp}/{url}", "timestamp": stamp}
original = build_pages.content_state(self.entry, self.data, {})
previous = {self.entry["cve"]: original}
# Records the page cannot render leave it as published.
for archives in ({}, {"https://github.com/owner/other": record}, {url: {**record, "timestamp": "20251021093001"}},
{url: {**record, "url": f"http://web.archive.org/web/{stamp}/{url}"}}):
with self.subTest(archives=archives):
self.assertEqual(build_pages.content_state(self.entry, {**self.data, "archives": archives}, previous),
original)
archived = build_pages.content_state(self.entry, {**self.data, "archives": {url: record}}, previous)
self.assertNotEqual(archived[0], original[0])
self.assertEqual(archived[1], self.data["today"])
later = {**self.data, "today": "2026-10-07"}
self.assertEqual(build_pages.content_state(self.entry, {**later, "archives": {url: {**record, "checked": "x"}}},
{self.entry["cve"]: archived}), archived)
self.assertEqual(build_pages.content_state(self.entry, later, {self.entry["cve"]: archived})[1], "2026-10-07")
def test_saved_files_advance_the_date_and_other_file_records_do_not(self) -> None:
url, cid = self.entry["poc"][0], self.entry["cve"]
def archived(files: object, data: dict = self.data) -> dict:
return {**data, "archives": {url: {"files": files}}}
original = build_pages.content_state(self.entry, self.data, {})
previous = {cid: original}
# Files the page cannot show leave it as published.
for files in ([], [saved_file(raw_file("poc.py", "owner/other"))], [saved_file(raw_file("poc.py", commit="main"))],
[{**saved_file(raw_file("poc.py")), "timestamp": "20261022161014"}],
[saved_file("https://hackerone.com/reports/123456.json")]):
with self.subTest(files=files):
self.assertEqual(build_pages.content_state(self.entry, archived(files), previous), original)
# A first saved file advances the page while its own snapshot is pending.
first = build_pages.content_state(self.entry, archived([saved_file(raw_file("poc.py"))]), previous)
self.assertNotEqual(first[0], original[0])
self.assertEqual(first[1], self.data["today"])
later = {**self.data, "today": "2026-10-07"}
# Order, repeats and older captures of the same file change nothing the page shows.
same = [saved_file(raw_file("poc.py"), "20261021120000"), saved_file(raw_file("poc.py")), saved_file(raw_file("poc.py"))]
self.assertEqual(build_pages.content_state(self.entry, archived(same, later), {cid: first}), first)
# A refreshed capture, or another file, does.
for files in ([saved_file(raw_file("poc.py"), "20261023100000")],
[saved_file(raw_file("poc.py")), saved_file(raw_file("lib.py"))]):
with self.subTest(files=files):
changed = build_pages.content_state(self.entry, archived(files, later), {cid: first})
self.assertNotEqual(changed[0], first[0])
self.assertEqual(changed[1], "2026-10-07")
# A file the page lists in a row of its own is not disclosed, or counted, twice.
listed = {**self.entry, "poc": [url, raw_file("poc.py")]}
self.assertEqual(build_pages.content_state(listed, archived([saved_file(raw_file("poc.py"))]), {}),
build_pages.content_state(listed, self.data, {}))
# Pages with a snapshot and no files keep the fingerprint they were published with.
snapshot = {"url": f"https://web.archive.org/web/20251021093000/{url}", "timestamp": "20251021093000"}
payload = {"entry": self.entry, "cvss": None, "advisories": None, "nuclei": None, "kev": None,
"archives": {url: [snapshot["url"], snapshot["timestamp"]]}}
self.assertEqual(build_pages.content_state(self.entry, {**self.data, "archives": {url: snapshot}}, {})[0],
build_pages.digest(payload))
def test_missing_manifest_bootstraps_but_outages_do_not_erase_state(self) -> None:
with patch.object(build_pages.request, "urlopen", side_effect=HTTPError("url", 404, "missing", {}, None)):
self.assertEqual(build_pages.previous_page_state(), {})
@@ -253,5 +324,290 @@ class RepositoryMetadataTests(unittest.TestCase):
self.assertNotIn("★", row)
class WaybackTests(unittest.TestCase):
URL = "https://github.com/owner/poc"
STAMP = "20251021093000"
SNAPSHOT = f"https://web.archive.org/web/{STAMP}/{URL}"
FILES_TITLE = "Wayback Machine captures of individual files at pinned commits, not a copy of the whole repository"
def render(self, entry: dict, archives: dict, repo_meta: dict | None = None, meta: dict | None = None) -> str:
data = {"cves": [entry], "meta": meta or {}, "epss": {}, "kev": {}, "nuclei": {}, "repo_meta": repo_meta or {},
"related": {}, "lastmod": {entry["cve"]: "2026-10-21"}, "archives": archives}
return build_pages.page(entry, data)
def test_cve_pages_link_confirmed_snapshots_and_label_lookups(self) -> None:
other = "https://www.exploit-db.com/exploits/50592"
advisory = "https://vendor.example/advisory"
entry = {"cve": "CVE-2026-1234", "desc": "Widget flaw", "poc": [self.URL], "edb": [other]}
markup = self.render(entry, {self.URL: {"url": self.SNAPSHOT, "timestamp": self.STAMP}},
meta={entry["cve"]: {"advisories": [[advisory, ["Vendor Advisory"]]]}})
self.assertIn(
'Repo metadata unavailable · '
f'<a class="wayback is-snapshot" href="{self.SNAPSHOT}" target="_blank" rel="nofollow noopener" '
'title="Wayback Machine page snapshot, captured 2025-10-21 09:30 UTC" '
'aria-label="snapshot of owner/poc on the Wayback Machine, captured 2025-10-21 09:30 UTC">snapshot</a>', markup)
self.assertIn(
f'<span><a class="wayback is-lookup" href="https://web.archive.org/web/*/{other}" target="_blank" '
'rel="nofollow noopener" title="Search the Wayback Machine for captures; none confirmed" '
f'aria-label="find archive of {other} on the Wayback Machine">find archive</a></span>', markup)
# The original stays the PoC link, counts are unchanged and advisories are not PoCs.
self.assertIn(f'<li><a href="{self.URL}" rel="nofollow noopener" target="_blank">owner/poc</a>', markup)
self.assertIn("<title>CVE-2026-1234: 2 public PoC exploits | PoC Index</title>", markup)
advisories = markup.split("<h2>Security advisories</h2>", 1)[1].split("</ul>", 1)[0]
self.assertIn(f'href="{advisory}"', advisories)
self.assertNotIn("wayback", advisories)
self.assertNotIn("web.archive.org/save", markup)
def test_untrusted_snapshot_records_fall_back_to_a_lookup(self) -> None:
url, stamp, snapshot = self.URL, self.STAMP, self.SNAPSHOT
for record in (
{"url": f"http://web.archive.org/web/{stamp}/{url}", "timestamp": stamp},
{"url": f"https://web.archive.org.example/web/{stamp}/{url}", "timestamp": stamp},
{"url": f"https://example.com/web.archive.org/web/{stamp}/{url}", "timestamp": stamp},
{"url": f"https://[email protected]/web/{stamp}/{url}", "timestamp": stamp},
{"url": f"https://web.archive.org/save/{url}", "timestamp": stamp},
{"url": f"https://web.archive.org/web/*/{url}", "timestamp": stamp},
{"url": f"https://web.archive.org/web/{stamp}id_/{url}", "timestamp": stamp},
{"url": f"https://web.archive.org/web/2025102109300/{url}", "timestamp": "2025102109300"},
{"url": f"https://web.archive.org/web/20250230093000/{url}", "timestamp": "20250230093000"},
{"url": f"https://web.archive.org/web/20251021240000/{url}", "timestamp": "20251021240000"},
{"url": f"https://web.archive.org/web/19951021093000/{url}", "timestamp": "19951021093000"},
{"url": snapshot, "timestamp": "20251021093001"},
{"url": snapshot, "timestamp": int(stamp)},
{"url": snapshot},
{"url": f"https://web.archive.org/web/{stamp}/javascript:alert(1)", "timestamp": stamp},
{"url": f"https://web.archive.org/web/{stamp}/https://example.com/poc", "timestamp": stamp},
{"url": f'{snapshot}"><script>alert(1)</script>', "timestamp": stamp},
{"url": f"{snapshot} onmouseover=alert(1)", "timestamp": stamp},
snapshot, None, [snapshot, stamp],
):
with self.subTest(record=record):
link = build_pages.archive_link(url, "owner/poc", {url: record})
self.assertIn(f'<a class="wayback is-lookup" href="https://web.archive.org/web/*/{url}"', link)
self.assertNotIn("is-snapshot", link)
self.assertNotIn("<script", link)
self.assertNotIn("onmouseover", link)
# The Wayback Machine may record the scheme, www. or default port differently.
canonical = {"url": f"https://web.archive.org/web/{stamp}/http://www.github.com:80/owner/poc", "timestamp": stamp}
self.assertIn('class="wayback is-snapshot"', build_pages.archive_link(url, "owner/poc", {url: canonical}))
def test_archive_links_escape_urls_and_labels(self) -> None:
url = "https://example.com/exploit?id=1&name='x'"
snapshot = f"https://web.archive.org/web/{self.STAMP}/{url}"
for archives, href, kind in (({}, f"https://web.archive.org/web/*/{url}", "is-lookup"),
({url: {"url": snapshot, "timestamp": self.STAMP}}, snapshot, "is-snapshot")):
with self.subTest(kind=kind):
markup = build_pages.archive_link(url, '<b>"label"</b>', archives)
(tag, attrs), = ParsedPage(markup).tags
self.assertEqual((tag, attrs["class"], attrs["href"]), ("a", f"wayback {kind}", href))
self.assertIn('<b>"label"</b>', attrs["aria-label"])
self.assertNotIn("<b>", markup)
def test_archived_fallbacks_link_their_snapshot_under_the_original_name(self) -> None:
original = "https://github.com/owner/gone-poc"
fallback = f"https://web.archive.org/web/20240101120000/{original}"
live = "https://github.com/owner/live"
collection = "https://github.com/google/security-research/tree/master/pocs/linux/kernelctf/CVE-2024-26642_lts"
entry = {"cve": "CVE-2026-1234", "desc": "Widget flaw", "poc": [live, fallback],
"collections": [f"https://web.archive.org/web/20240101120000/{collection}"]}
markup = self.render(entry, {original: {"url": fallback, "timestamp": "20240101120000"}},
{"owner/gone-poc": [50, "2024-01-01"], "owner/live": [10, "2026-10-01"]})
stamp = ('<span class="wayback is-archived" title="Wayback Machine page snapshot captured 2024-01-01 12:00 UTC, '
'linked in place of the original" aria-hidden="true">ARCHIVED</span>')
rows = re.findall(r'<li><a href="([^"]*)"([^>]*)>([^<]*)</a>(?:<span>(.*?)</span>)?</li>', markup)
# Ranked, named and measured as the original, linked to the snapshot.
self.assertEqual(rows[:3], [
(fallback, ' rel="nofollow noopener" target="_blank" '
'aria-label="owner/gone-poc, archived page snapshot captured 2024-01-01 12:00 UTC"',
"owner/gone-poc", f"Repo stars 50★ · pushed 2024-01-01 · {stamp}"),
(live, ' rel="nofollow noopener" target="_blank"', "owner/live",
"Repo stars 10★ · pushed 2026-10-01 · "
f'<a class="wayback is-lookup" href="https://web.archive.org/web/*/{live}" target="_blank" rel="nofollow noopener" '
'title="Search the Wayback Machine for captures; none confirmed" '
'aria-label="find archive of owner/live on the Wayback Machine">find archive</a>'),
(f"https://web.archive.org/web/20240101120000/{collection}",
' rel="noopener" target="_blank" aria-label="linux/kernelctf/CVE-2024-26642_lts, archived page snapshot '
'captured 2024-01-01 12:00 UTC"',
"linux/kernelctf/CVE-2024-26642_lts", f"google/security-research · Repo metadata unavailable · {stamp}"),
])
self.assertNotIn(f'href="{original}"', markup)
self.assertNotIn(f'href="{collection}"', markup)
self.assertNotIn("/web/*/https://web.archive.org", markup)
self.assertIn("3 public PoC exploits", markup)
def test_cve_pages_disclose_saved_files_beside_snapshots_and_lookups(self) -> None:
pending = "https://github.com/Owner/Other-PoC"
report = "https://hackerone.com/reports/123456"
newest, spaced, report_json = (saved_file(raw_file("poc.py")), saved_file(raw_file("src/exploit%20one.py")),
saved_file(f"{report}.json"))
entry = {"cve": "CVE-2026-1234", "desc": "Widget flaw", "poc": [self.URL, pending, report]}
markup = self.render(entry, {
# One capture per file, the latest, however often the record lists it.
self.URL: {"url": self.SNAPSHOT, "timestamp": self.STAMP,
"files": [spaced, saved_file(raw_file("poc.py"), "20261021120000"), newest, newest]},
# A page whose own snapshot is still pending.
pending: {"files": [saved_file(raw_file("run.sh", "owner/other-poc"))]},
report: {"files": [report_json]},
# Each file is also listed under its own original, which is no row.
newest["original"]: {"url": newest["url"], "timestamp": newest["timestamp"]},
})
self.assertIn(
'aria-label="snapshot of owner/poc on the Wayback Machine, captured 2025-10-21 09:30 UTC">snapshot</a></span>'
f'<details class="sources" style="--files:2" data-sources="{self.URL}"><summary title="{self.FILES_TITLE}" '
'aria-label="2 files saved from owner/poc">2 files</summary><div class="sources-list">'
f'<a href="{newest["url"]}" target="_blank" rel="nofollow noopener" '
'title="Wayback Machine capture of poc.py at commit 0123456, 2026-10-22 16:10 UTC" '
'aria-label="poc.py at commit 0123456 of owner/poc, Wayback Machine capture 2026-10-22 16:10 UTC">poc.py</a>'
f'<a href="{spaced["url"]}" target="_blank" rel="nofollow noopener" '
'title="Wayback Machine capture of src/exploit one.py at commit 0123456, 2026-10-22 16:10 UTC" '
'aria-label="src/exploit one.py at commit 0123456 of owner/poc, Wayback Machine capture 2026-10-22 16:10 UTC">'
"src/exploit one.py</a></div></details></li>", markup)
self.assertNotIn("20261021120000", markup)
self.assertIn(
f'find archive</a></span><details class="sources" style="--files:1" data-sources="{pending}">'
f'<summary title="{self.FILES_TITLE}" aria-label="1 file saved from Owner/Other-PoC">1 file</summary>', markup)
self.assertIn(
f'find archive</a></span><details class="sources" style="--files:1" data-sources="{report}">'
f'<summary title="Wayback Machine capture of the report JSON" aria-label="1 file saved from {report}">1 file</summary>'
f'<div class="sources-list"><a href="{report_json["url"]}" target="_blank" rel="nofollow noopener" '
'title="Wayback Machine capture of 123456.json, the report JSON, 2026-10-22 16:10 UTC" '
f'aria-label="123456.json, the report JSON of {report}, Wayback Machine capture 2026-10-22 16:10 UTC">'
"123456.json</a></div></details></li>", markup)
# Saved files are no PoCs of their own, and nothing saved is looked up again.
self.assertIn("<title>CVE-2026-1234: 3 public PoC exploits | PoC Index</title>", markup)
self.assertEqual(markup.count('class="wayback '), 3)
self.assertEqual(markup.count("<details "), 3)
self.assertNotRegex(markup, r"/web/\*/https://(?:web\.archive\.org|raw\.githubusercontent\.com|hackerone\.com/reports/123456\.json)")
def test_saved_files_must_be_captures_of_the_linked_pages_own_files(self) -> None:
good = saved_file(raw_file("poc.py"))
stamp = good["timestamp"]
def disclosed(parent: str, files: object) -> str:
return build_pages.source_files(parent, "label", {parent: {"files": files}})
# GitHub names repositories without regard to case or a .git suffix.
for parent in (self.URL, "https://github.com/Owner/POC.git", "https://www.github.com/owner/poc/blob/main/README.md"):
with self.subTest(parent=parent):
self.assertIn("1 file</summary>", disclosed(parent, [good]))
for file in (
saved_file(raw_file("poc.py", "owner/other")),
saved_file(raw_file("poc.py", "other/poc")),
saved_file(raw_file("poc.py", commit="main")),
saved_file(raw_file("poc.py", commit=COMMIT[1:])),
saved_file(raw_file("poc.py", commit=COMMIT.upper())),
# A dot segment would open another repository's file.
saved_file(raw_file(f"../../other/poc/{COMMIT}/poc.py")),
saved_file(raw_file("%2e%2E/poc.py")),
saved_file(raw_file("./poc.py")),
saved_file(raw_file("src//poc.py")),
saved_file(raw_file("poc.py?token=1")),
saved_file(raw_file("poc.py#L1")),
saved_file(f"http://raw.githubusercontent.com/owner/poc/{COMMIT}/poc.py"),
saved_file(f"https://raw.githubusercontent.com.example/owner/poc/{COMMIT}/poc.py"),
saved_file(f"https://gist.githubusercontent.com/owner/poc/raw/{COMMIT}/poc.py"),
saved_file(f"https://github.com/owner/poc/blob/{COMMIT}/poc.py"),
saved_file(f"https://example.com/owner/poc/{COMMIT}/poc.py"),
saved_file("https://hackerone.com/reports/123456.json"),
# An archive link is never saved again.
saved_file(good["url"]),
{**good, "url": saved_file(raw_file("other.py"))["url"]},
{**good, "url": f"https://web.archive.org/web/{stamp}/https://example.com/owner/poc/{COMMIT}/poc.py"},
{**good, "timestamp": "20261022161014"},
{**good, "timestamp": int(stamp)},
{**good, "url": f"https://web.archive.org/web/{stamp}id_/{good['original']}"},
{**good, "url": f"https://web.archive.org/web/*/{good['original']}"},
{**good, "url": f"http://web.archive.org/web/{stamp}/{good['original']}"},
{**good, "url": f"https://web.archive.org/web/20250230093000/{good['original']}", "timestamp": "20250230093000"},
{"url": good["url"], "timestamp": stamp},
good["url"], None, [good],
):
with self.subTest(file=file):
self.assertEqual(disclosed(self.URL, [file]), "")
for files in (good, "files", None, {}):
with self.subTest(files=files):
self.assertEqual(disclosed(self.URL, files), "")
# Advisories, gists, other hosts and files themselves hold no repository files.
for parent in ("https://github.com/owner/poc/security/advisories/GHSA-1234-5678-9abc",
"https://gist.github.com/owner/0123", "https://example.com/owner/poc", good["original"]):
with self.subTest(parent=parent):
self.assertEqual(disclosed(parent, [good]), "")
# A HackerOne report holds its own report JSON and nothing else.
report_json = saved_file("https://hackerone.com/reports/123456.json")
for parent in ("https://hackerone.com/reports/123456", "https://www.hackerone.com/reports/123456/",
"https://hackerone.com/reports/123456?subject=x"):
with self.subTest(parent=parent):
self.assertIn("1 file</summary>", disclosed(parent, [report_json]))
for parent, file in (
("https://hackerone.com/reports/123456", saved_file("https://hackerone.com/reports/654321.json")),
("https://hackerone.com/reports/123456", saved_file("https://hackerone.example/reports/123456.json")),
("https://hackerone.com/reports/123456", saved_file("https://hackerone.com/reports/123456")),
("https://hackerone.com/reports/123456", saved_file("https://hackerone.com/reports/123456.json?x=1")),
("https://hackerone.com/reports/123456", good),
("https://hackerone.com/reports/123456.json", report_json),
("https://hackerone.com/bugs?report_id=123456", report_json),
("https://example.com/reports/123456", report_json),
):
with self.subTest(parent=parent, file=file):
self.assertEqual(disclosed(parent, [file]), "")
def test_saved_file_names_links_and_labels_are_escaped(self) -> None:
odd = saved_file(raw_file("x%22%3E%3Cimg%20src%3Dx%20onerror%3Dalert(1)%3E/it's.py"))
malformed = saved_file(raw_file("100%.py"))
markup =build_pages.source_files(self.URL, '<b>"label"</b>', {self.URL: {"files": [odd, malformed]}})
page = ParsedPage(markup)
self.assertEqual([tag for tag, _ in page.tags], ["details", "summary", "div", "a", "a"])
self.assertEqual(page.tags[1][1]["aria-label"], '2 files saved from <b>"label"</b>')
links = [attrs for tag, attrs in page.tags if tag == "a"]
self.assertEqual([attrs["href"] for attrs in links], [malformed["url"], odd["url"]])
self.assertEqual(links[1]["aria-label"], 'x"><img src=x onerror=alert(1)>/it\'s.py at commit 0123456 of '
'<b>"label"</b>, Wayback Machine capture 2026-10-22 16:10 UTC')
# A malformed escape is shown as written.
self.assertEqual(page.text[1:], ["100%.py", 'x"><img src=x onerror=alert(1)>/it\'s.py'])
self.assertNotIn("<img", markup)
self.assertNotIn("<b>", markup)
def test_archived_fallbacks_disclose_their_original_saved_files_once(self) -> None:
original = "https://github.com/owner/gone-poc"
fallback = f"https://web.archive.org/web/20240101120000/{original}"
exploit = saved_file(raw_file("exploit.c", "owner/gone-poc"))
listed, helper = saved_file(raw_file("poc.py")), saved_file(raw_file("helper.py"))
entry = {"cve": "CVE-2026-1234", "desc": "Widget flaw", "poc": [fallback, self.URL, listed["original"]]}
archives = {original: {"url": fallback, "timestamp": "20240101120000", "files": [exploit]},
self.URL: {"files": [listed, helper]},
listed["original"]: {"url": listed["url"], "timestamp": listed["timestamp"]}}
markup = self.render(entry, archives)
self.assertIn('linked in place of the original" aria-hidden="true">ARCHIVED</span></span>'
f'<details class="sources" style="--files:1" data-sources="{fallback}"><summary', markup)
self.assertIn(f'<a href="{exploit["url"]}" target="_blank" rel="nofollow noopener" '
'title="Wayback Machine capture of exploit.c at commit 0123456, 2026-10-22 16:10 UTC" '
'aria-label="exploit.c at commit 0123456 of owner/gone-poc, Wayback Machine capture '
'2026-10-22 16:10 UTC">exploit.c</a>', markup)
# The lost original is never linked, and no capture is looked up again.
self.assertNotIn(f'href="{original}"', markup)
self.assertNotRegex(markup, r"/web/\*/https://(?:web\.archive\.org|raw\.githubusercontent\.com)")
# poc.py has a row and a snapshot of its own, so its page discloses only helper.py.
self.assertIn('aria-label="1 file saved from owner/poc">1 file</summary>', markup)
self.assertIn(f'<a href="{helper["url"]}"', markup)
self.assertEqual(markup.count(f'href="{listed["url"]}"'), 1)
self.assertIn("3 public PoC exploits", markup)
# The page's fingerprint follows the files it shows.
data = {"today": "2026-10-21", "meta": {}, "nuclei": {}, "kev": {}, "repo_meta": {}}
without = {**archives, original: {"url": fallback, "timestamp": "20240101120000"}}
self.assertNotEqual(build_pages.content_state(entry, {**data, "archives": archives}, {})[0],
build_pages.content_state(entry, {**data, "archives": without}, {})[0])
def test_a_missing_archive_index_is_empty_and_a_malformed_one_stops_the_build(self) -> None:
with tempfile.TemporaryDirectory() as directory, patch.object(build_pages, "DOCS", directory):
self.assertEqual(build_pages.load_optional("archives.json"), {})
index = Path(directory, "archives.json")
records = {self.URL: {"url": self.SNAPSHOT, "timestamp": self.STAMP}}
index.write_text(json.dumps(records), encoding="utf-8")
self.assertEqual(build_pages.load_optional("archives.json"), records)
index.write_text("[]", encoding="utf-8")
with self.assertRaisesRegex(ValueError, "archives.json"):
build_pages.load_optional("archives.json")
if __name__ == "__main__":
unittest.main()
+66 -5
View File
@@ -77,8 +77,10 @@ const context = vm.createContext({
location: { pathname: '/', search: '' },
window: { matchMedia: () => ({ matches: false }) },
setTimeout() {}, clearTimeout() {},
fetch: url => url === '/trending_poc.json'
? Promise.resolve({ ok: true, json: async () => input.feed })
// With archives, an empty index lets the archive download that follows it run.
fetch: url => url === '/trending_poc.json' ? Promise.resolve({ ok: true, json: async () => input.feed })
: input.archives && url === '/CVE_list.json' ? Promise.resolve({ ok: true, json: async () => [] })
: input.archives && url === '/archives.json' ? Promise.resolve({ ok: true, json: async () => input.archives })
: new Promise(() => {})
});
vm.runInContext(fs.readFileSync(input.script, 'utf8'), context);
@@ -100,12 +102,13 @@ setImmediate(() => {
"""
def browser(feed: dict) -> dict:
"""What logic.js shows once the feed arrives, then for each switch value."""
def browser(feed: dict, archives: dict | None = None) -> dict:
"""What logic.js shows once the feed, and any archive index, arrives, then
for each switch value."""
node = shutil.which("node")
if node is None:
raise unittest.SkipTest("node renders the browser lists")
payload = {"script": str(ROOT / "docs" / "logic.js"), "feed": feed, "now": NOW.isoformat()}
payload = {"script": str(ROOT / "docs" / "logic.js"), "feed": feed, "now": NOW.isoformat(), "archives": archives}
done = subprocess.run([node, "-e", HARNESS], input=json.dumps(payload), capture_output=True,
text=True, timeout=60)
if done.returncode:
@@ -191,6 +194,64 @@ class HomepageListTests(unittest.TestCase):
self.assertEqual([self.views[mode]["pressed"] for mode in ("initial", "TRENDING", "RECENT")],
[["true", "false"], ["false", "true"], ["true", "false"]])
def test_wayback_snapshots_and_lookups_match_in_browser_and_prerender(self) -> None:
stamp = "20261006160000"
archives = {
SHARED: {"url": f"https://web.archive.org/web/{stamp}/{SHARED}", "timestamp": stamp},
# Recorded with another scheme, www. and port: still this page.
LANDED[2]["url"]: {"url": f"https://web.archive.org/web/{stamp}/http://exploit-db.com:80/exploits/50592",
"timestamp": stamp},
# Another site's capture is not this link's snapshot.
KERNELCTF + "mitigation": {"url": f"https://web.archive.org/web/{stamp}/https://example.com/", "timestamp": stamp},
}
views = browser(FEED, archives)
landed = build_pages.trend_rows(LANDED, True, NOW, archives)
self.assertEqual(views["initial"]["rows"], as_browser(landed))
self.assertEqual(views["TRENDING"]["rows"], as_browser(build_pages.trend_rows(TRENDING, False, NOW, archives)))
self.assertIn(landed, build_pages.homepage(INDEXED, {}, FEED, NOW, archives))
self.assertEqual(landed.count('class="wayback is-snapshot"'), 2)
self.assertIn(f'<a class="wayback is-lookup" href="https://web.archive.org/web/*/{KERNELCTF}mitigation"', landed)
self.assertIn('aria-label="snapshot of CVE-2026-21589 on the Wayback Machine, captured 2026-10-06 16:00 UTC"', landed)
# Everything else in the rows reads as it does without archives.
self.assertEqual(cells(views["initial"]["rows"]), cells(self.views["LANDED"]["rows"]))
def test_saved_files_match_in_browser_and_prerender(self) -> None:
stamp, commit = "20261006160000", "0123456789abcdef0123456789abcdef01234567"
exploit = (f"https://raw.githubusercontent.com/google/security-research/{commit}/"
"pocs/linux/kernelctf/CVE-2024-26642_mitigation/exploit.c")
poc = f"https://raw.githubusercontent.com/owner/cve-2026-21589/{commit}/poc.py"
def saved(original: str) -> dict:
return {"original": original, "url": f"https://web.archive.org/web/{stamp}/{original}", "timestamp": stamp}
archives = {
SHARED: {"url": f"https://web.archive.org/web/{stamp}/{SHARED}", "timestamp": stamp, "files": [saved(poc)]},
# Saved files while the page snapshot is pending.
KERNELCTF + "mitigation": {"files": [saved(exploit)]},
# Not this page's file.
LANDED[2]["url"]: {"files": [saved(poc)]},
}
views = browser(FEED, archives)
landed = build_pages.trend_rows(LANDED, True, NOW, archives)
trending = build_pages.trend_rows(TRENDING, False, NOW, archives)
self.assertEqual(views["initial"]["rows"], as_browser(landed))
self.assertEqual(views["TRENDING"]["rows"], as_browser(trending))
self.assertIn(landed, build_pages.homepage(INDEXED, {}, FEED, NOW, archives))
self.assertEqual((landed.count("<details "), trending.count("<details ")), (2, 1))
self.assertIn(
f'find archive</a><details class="sources" style="--files:1" data-sources="{KERNELCTF}mitigation">'
'<summary title="Wayback Machine captures of individual files at pinned commits, not a copy of the whole '
'repository" aria-label="1 file saved from CVE-2024-26642_mitigation">1 file</summary>'
f'<div class="sources-list"><a href="https://web.archive.org/web/{stamp}/{exploit}" target="_blank" '
'rel="nofollow noopener" title="Wayback Machine capture of pocs/linux/kernelctf/CVE-2024-26642_mitigation/'
'exploit.c at commit 0123456, 2026-10-06 16:00 UTC" aria-label="pocs/linux/kernelctf/CVE-2024-26642_mitigation/'
'exploit.c at commit 0123456 of CVE-2024-26642_mitigation, Wayback Machine capture 2026-10-06 16:00 UTC">'
'pocs/linux/kernelctf/CVE-2024-26642_mitigation/exploit.c</a></div></details></div></div>', landed)
self.assertIn(f'snapshot</a><details class="sources" style="--files:1" data-sources="{SHARED}">', trending)
# Everything else in the rows reads as it does without archives.
self.assertEqual(cells(views["initial"]["rows"]), cells(self.views["LANDED"]["rows"]))
self.assertEqual(cells(views["TRENDING"]["rows"]), cells(self.views["TRENDING"]["rows"]))
def test_an_empty_list_shows_the_empty_state_in_both(self) -> None:
empty = build_pages.trend_rows([], True)
self.assertIn("No recent PoCs.", empty)
+385 -2
View File
@@ -9,7 +9,8 @@ const { MessageChannel } = require('node:worker_threads');
const script = fs.readFileSync(path.join(__dirname, '../docs/logic.js'), 'utf8');
function startPage(t, { search = '', trending, kev = {}, repositories = {}, indexError = false, cvssError = false, entries }) {
function startPage(t, { search = '', trending, kev = {}, repositories = {}, archives = {}, published = [],
indexError = false, cvssError = false, archivesError = false, entries }) {
const elements = new Map();
const calls = [];
const document = {
@@ -19,7 +20,9 @@ function startPage(t, { search = '', trending, kev = {}, repositories = {}, inde
if (!elements.has(selector)) elements.set(selector, {
value: '',
innerHTML: selector === '[data-trend-rows]' ? '<a href="/CVE-2026-1234">Prerendered PoC</a>' : '',
addEventListener() {}, setAttribute() {}, querySelectorAll: () => []
addEventListener() {}, setAttribute() {},
// The snapshot links a prerendered homepage carries.
querySelectorAll: () => selector === '[data-trend-rows]' ? published : []
});
return elements.get(selector);
}
@@ -33,9 +36,11 @@ function startPage(t, { search = '', trending, kev = {}, repositories = {}, inde
calls.push(url);
if (url === '/CVE_list.json' && indexError) throw new Error('Index unavailable');
if (url === '/cvss.json' && cvssError) throw new Error('CVSS unavailable');
if (url === '/archives.json' && archivesError) throw new Error('Archive index unavailable');
const data = url === '/trending_poc.json' ? await trending
: url === '/kev.json' ? await kev
: url === '/repo_meta.json' ? await repositories
: url === '/archives.json' ? await archives
: url === '/CVE_list.json' ? entries || [{ cve: 'CVE-2026-1234', desc: 'widget', poc: ['https://github.com/owner/poc'] }]
: {};
return { ok: true, json: async () => data };
@@ -55,6 +60,13 @@ async function searchFixture(t, entries, options = {}) {
};
}
// A source file saved at a pinned commit, as archives.json lists it under its page.
const COMMIT = '0123456789abcdef0123456789abcdef01234567';
const rawFile = (path, repository = 'owner/poc', commit = COMMIT) =>
`https://raw.githubusercontent.com/${repository}/${commit}/${path}`;
const savedFile = (original, stamp = '20261022161013') =>
({ original, url: `https://web.archive.org/web/${stamp}/${original}`, timestamp: stamp });
test('repository name prefixes beat incidental prose without joining numbered filenames', async t => {
const search = await searchFixture(t, [
{ cve: 'CVE-2004-0660', desc: 'XSS in (1) show_archives.php, (2) show_news.php', edb: ['https://www.exploit-db.com/exploits/24238'] },
@@ -366,6 +378,377 @@ test('curated artifact paths survive search rendering without duplicate reposito
assert.equal(vm.runInContext(`normalizedLink(${JSON.stringify(variants[0])}) === normalizedLink(${JSON.stringify(base)})`, context), true);
});
test('PoC rows link a confirmed Wayback snapshot and otherwise offer a labelled lookup', async t => {
const archived = 'https://github.com/owner/archived-poc';
const other = 'https://www.exploit-db.com/exploits/50592';
const snapshot = `https://web.archive.org/web/20251021093000/${archived}`;
const entries = [{ cve: 'CVE-2026-1234', desc: 'widget', poc: [archived], edb: [other] }];
const { elements } = startPage(t, { search: '?q=widget', entries, trending: new Promise(() => {}),
archives: { [archived]: { url: snapshot, timestamp: '20251021093000' } } });
await new Promise(setImmediate);
const html = elements.get('[data-results]').innerHTML;
assert.ok(html.includes(`<a class="wayback is-snapshot" href="${snapshot}" target="_blank" rel="nofollow noopener" ` +
'title="Wayback Machine page snapshot, captured 2025-10-21 09:30 UTC" ' +
'aria-label="snapshot of owner/archived-poc on the Wayback Machine, captured 2025-10-21 09:30 UTC">snapshot</a>'));
assert.ok(html.includes(`<a class="wayback is-lookup" href="https://web.archive.org/web/*/${other}" target="_blank" rel="nofollow noopener" ` +
'title="Search the Wayback Machine for captures; none confirmed" ' +
'aria-label="find archive of exploit-db.com/50592 on the Wayback Machine">find archive</a>'));
assert.equal(html.match(/class="wayback /g).length, 2);
// The original stays the PoC link and the count is unchanged.
assert.ok(html.includes(`<a href="${archived}" target="_blank" rel="nofollow noopener">archived-poc</a>`));
assert.match(html, /2 linked PoCs/);
assert.doesNotMatch(html, /web\.archive\.org\/save/);
});
test('malformed or untrusted snapshot records fall back to a lookup and links are escaped', async t => {
const { context } = startPage(t, { trending: new Promise(() => {}) });
await new Promise(setImmediate);
const url = 'https://github.com/owner/poc';
const stamp = '20251021093000';
const snapshot = `https://web.archive.org/web/${stamp}/${url}`;
const untrusted = [
{ url: `http://web.archive.org/web/${stamp}/${url}`, timestamp: stamp },
{ url: `https://web.archive.org.example/web/${stamp}/${url}`, timestamp: stamp },
{ url: `https://example.com/web.archive.org/web/${stamp}/${url}`, timestamp: stamp },
{ url: `https://[email protected]/web/${stamp}/${url}`, timestamp: stamp },
{ url: `https://web.archive.org/save/${url}`, timestamp: stamp },
{ url: `https://web.archive.org/web/*/${url}`, timestamp: stamp },
{ url: `https://web.archive.org/web/${stamp}id_/${url}`, timestamp: stamp },
{ url: `https://web.archive.org/web/2025102109300/${url}`, timestamp: '2025102109300' },
{ url: `https://web.archive.org/web/20250230093000/${url}`, timestamp: '20250230093000' },
{ url: `https://web.archive.org/web/20251021240000/${url}`, timestamp: '20251021240000' },
{ url: `https://web.archive.org/web/19951021093000/${url}`, timestamp: '19951021093000' },
{ url: snapshot, timestamp: '20251021093001' },
{ url: snapshot, timestamp: Number(stamp) },
{ url: snapshot },
{ url: `https://web.archive.org/web/${stamp}/javascript:alert(1)`, timestamp: stamp },
{ url: `https://web.archive.org/web/${stamp}/https://example.com/poc`, timestamp: stamp },
{ url: `${snapshot}"><script>alert(1)</script>`, timestamp: stamp },
{ url: `${snapshot} onmouseover=alert(1)`, timestamp: stamp },
snapshot, null, [snapshot, stamp]
];
for (const record of untrusted) {
context.record = record;
const row = vm.runInContext(`archives = { ${JSON.stringify(url)}: record }; pocRow(${JSON.stringify(url)})`, context);
assert.ok(row.includes(`<a class="wayback is-lookup" href="https://web.archive.org/web/*/${url}"`), JSON.stringify(record));
assert.doesNotMatch(row, /is-snapshot|<script|onmouseover/);
}
// The Wayback Machine may record the scheme, www. or default port differently.
context.record = { url: `https://web.archive.org/web/${stamp}/http://www.github.com:80/owner/poc`, timestamp: stamp };
assert.match(vm.runInContext(`archives = { ${JSON.stringify(url)}: record }; pocRow(${JSON.stringify(url)})`, context),
/class="wayback is-snapshot"/);
const query = "https://example.com/exploit?id=1&name='x'";
context.record = { url: `https://web.archive.org/web/${stamp}/${query}`, timestamp: stamp };
const linked = vm.runInContext(`archives = { ${JSON.stringify(query)}: record }; archiveLink(${JSON.stringify(query)}, '<b>"label"</b>')`, context);
assert.ok(linked.includes(`href="https://web.archive.org/web/${stamp}/https://example.com/exploit?id=1&amp;name=&#39;x&#39;"`));
assert.ok(linked.includes('aria-label="snapshot of &lt;b&gt;&quot;label&quot;&lt;/b&gt; on the Wayback Machine, captured 2025-10-21 09:30 UTC"'));
const lookup = vm.runInContext(`archives = {}; archiveLink(${JSON.stringify(query)}, 'label')`, context);
assert.ok(lookup.includes('href="https://web.archive.org/web/*/https://example.com/exploit?id=1&amp;name=&#39;x&#39;"'));
});
test('an archived fallback stands in for its original without a second archive link', async t => {
const original = 'https://github.com/owner/php2shell-poc';
const fallback = `https://web.archive.org/web/20240101120000/${original}`;
const live = 'https://github.com/owner/live';
const entries = [
{ cve: 'CVE-2026-1000', desc: 'Pending details', poc: [live, fallback] },
{ cve: 'CVE-2026-2000', desc: 'A report mentions php2shell in passing.', poc: ['https://github.com/owner/unrelated'] }
];
const { context, elements } = startPage(t, { search: '?q=php2shell', entries, trending: new Promise(() => {}),
repositories: { 'owner/php2shell-poc': [50, '2024-01-01'], 'owner/live': [10, '2026-10-01'] },
archives: { [original]: { url: fallback, timestamp: '20240101120000' } } });
while (!vm.runInContext('wordIndex.ready', context)) await new Promise(setImmediate);
await new Promise(setImmediate);
const search = (query, scan = false) => {
context.query = query;
return Array.from(vm.runInContext(`runSearch(query, ${scan})`, context), row => row.cve);
};
// Matched, filtered and ranked as the original would be, not as web.archive.org.
assert.deepEqual(search('php2shell'), ['CVE-2026-1000', 'CVE-2026-2000']);
assert.deepEqual(search('php2shell'), search('php2shell', true));
assert.deepEqual(search('archive'), []);
assert.deepEqual([...vm.runInContext('entrySources(dataset[0])', context)], ['GITHUB']);
assert.deepEqual(Array.from(vm.runInContext('rankedLinks(dataset[0])', context)), [fallback, live]);
const html = elements.get('[data-results]').innerHTML;
assert.match(html, /2 linked PoCs/);
assert.ok(html.includes(`owner<span class="poc-sep"> / </span><a href="${fallback}" ` +
'aria-label="php2shell-poc, archived page snapshot captured 2024-01-01 12:00 UTC" target="_blank" rel="nofollow noopener">php2shell-poc</a>'));
assert.ok(html.includes('<span class="wayback is-archived" title="Wayback Machine page snapshot captured 2024-01-01 12:00 UTC, ' +
'linked in place of the original" aria-hidden="true">ARCHIVED</span>'));
// The lost original is never linked, and the snapshot gets no archive link of its own.
assert.ok(!html.includes(`href="${original}"`));
assert.ok(!html.includes(`/web/*/${fallback}`));
assert.equal(html.match(/class="wayback is-lookup"/g).length, 2);
const template = 'https://github.com/projectdiscovery/nuclei-templates/blob/main/http/cves/2021/CVE-2021-44228.yaml';
assert.match(vm.runInContext(`pocRow('https://web.archive.org/web/20240101120000/${template}', true)`, context),
/<span class="poc-tag is-nuclei"[^>]*>NUCLEI<\/span><a href="https:\/\/web\.archive\.org\/web\/20240101120000\/https:[^"]+" aria-label="CVE-2021-44228\.yaml, archived page snapshot captured 2024-01-01 12:00 UTC"[^>]*>CVE-2021-44228\.yaml<\/a>/);
// Other archive links, readable or not, get no Wayback control at all.
for (const url of ['https://web.archive.org/web/2011/https://example.com/old', 'https://archive.org/details/exploit-kit']) {
assert.doesNotMatch(vm.runInContext(`pocRow(${JSON.stringify(url)})`, context), /class="wayback/);
}
});
test('saved files are disclosed beside a snapshot or a lookup without counting as PoCs', async t => {
const repo = 'https://github.com/owner/poc';
const pending = 'https://github.com/Owner/Other-PoC';
const report = 'https://hackerone.com/reports/123456';
const live = 'https://github.com/owner/live';
const page = `https://web.archive.org/web/20261022160913/${repo}`;
const newest = savedFile(rawFile('poc.py'));
const spaced = savedFile(rawFile('src/exploit%20one.py'));
const json = savedFile(`${report}.json`);
const entries = [{ cve: 'CVE-2026-1234', desc: 'widget', poc: [repo, pending, report, live] }];
const archives = {
// One capture per file, the latest, however often the record lists it.
[repo]: { url: page, timestamp: '20261022160913',
files: [spaced, savedFile(rawFile('poc.py'), '20261021120000'), newest, newest] },
// A page whose own snapshot is still pending.
[pending]: { files: [savedFile(rawFile('run.sh', 'owner/other-poc'))] },
[report]: { files: [json] },
// Each file is also listed under its own original, which is no row.
[newest.original]: { url: newest.url, timestamp: newest.timestamp }
};
const { elements } = startPage(t, { search: '?q=widget', entries, archives, trending: new Promise(() => {}),
repositories: { 'owner/live': [90, '2026-10-01'], 'owner/poc': [50, '2026-10-01'], 'owner/other-poc': [10, '2026-10-01'] } });
await new Promise(setImmediate);
const html = elements.get('[data-results]').innerHTML;
// Rows keep their star order and count, and each keeps one Wayback control.
const order = [live, repo, pending, report].map(url => html.indexOf(`href="${url}"`));
assert.ok(order[0] >= 0);
assert.deepEqual([...order].sort((a, b) => a - b), order);
assert.match(html, /4 linked PoCs/);
assert.equal(html.match(/class="wayback /g).length, 4);
assert.equal(html.match(/<details /g).length, 3);
assert.ok(html.includes(`<div class="poc-archive"><a class="wayback is-snapshot" href="${page}"`));
assert.ok(html.includes('snapshot</a><details class="sources" style="--files:2" data-sources="https://github.com/owner/poc">' +
'<summary title="Wayback Machine captures of individual files at pinned commits, not a copy of the whole repository" ' +
'aria-label="2 files saved from owner/poc">2 files</summary><div class="sources-list">' +
`<a href="${newest.url}" target="_blank" rel="nofollow noopener" ` +
'title="Wayback Machine capture of poc.py at commit 0123456, 2026-10-22 16:10 UTC" ' +
'aria-label="poc.py at commit 0123456 of owner/poc, Wayback Machine capture 2026-10-22 16:10 UTC">poc.py</a>' +
`<a href="${spaced.url}" target="_blank" rel="nofollow noopener" ` +
'title="Wayback Machine capture of src/exploit one.py at commit 0123456, 2026-10-22 16:10 UTC" ' +
'aria-label="src/exploit one.py at commit 0123456 of owner/poc, Wayback Machine capture 2026-10-22 16:10 UTC">' +
'src/exploit one.py</a></div></details></div>'));
assert.ok(!html.includes('20261021120000'));
assert.ok(html.includes(`find archive</a><details class="sources" style="--files:1" data-sources="${pending}">` +
'<summary title="Wayback Machine captures of individual files at pinned commits, not a copy of the whole repository" ' +
'aria-label="1 file saved from Owner/Other-PoC">1 file</summary>'));
assert.ok(html.includes(`find archive</a><details class="sources" style="--files:1" data-sources="${report}">` +
'<summary title="Wayback Machine capture of the report JSON" aria-label="1 file saved from hackerone.com/reports/123456">' +
`1 file</summary><div class="sources-list"><a href="${json.url}" target="_blank" rel="nofollow noopener" ` +
'title="Wayback Machine capture of 123456.json, the report JSON, 2026-10-22 16:10 UTC" ' +
'aria-label="123456.json, the report JSON of hackerone.com/reports/123456, Wayback Machine capture 2026-10-22 16:10 UTC">' +
'123456.json</a></div></details>'));
// No saved file or snapshot is looked up again.
assert.doesNotMatch(html, /\/web\/\*\/https:\/\/(?:web\.archive\.org|raw\.githubusercontent\.com|hackerone\.com\/reports\/123456\.json)/);
});
test('saved files must be captures of the linked page\'s own files', async t => {
const { context } = startPage(t, { trending: new Promise(() => {}) });
await new Promise(setImmediate);
const disclosed = (parent, files) => {
context.record = { files };
return vm.runInContext(`archives = { ${JSON.stringify(parent)}: record }; sourceFiles(${JSON.stringify(parent)}, 'label')`, context);
};
const repo = 'https://github.com/owner/poc';
const good = savedFile(rawFile('poc.py'));
const stamp = good.timestamp;
// GitHub names repositories without regard to case or a .git suffix.
for (const parent of [repo, 'https://github.com/Owner/POC.git', 'https://www.github.com/owner/poc/blob/main/README.md']) {
assert.match(disclosed(parent, [good]), /1 file<\/summary>/, parent);
}
for (const file of [
savedFile(rawFile('poc.py', 'owner/other')),
savedFile(rawFile('poc.py', 'other/poc')),
savedFile(rawFile('poc.py', 'owner/poc', 'main')),
savedFile(rawFile('poc.py', 'owner/poc', COMMIT.slice(1))),
savedFile(rawFile('poc.py', 'owner/poc', COMMIT.toUpperCase())),
// A dot segment would open another repository's file.
savedFile(rawFile(`../../other/poc/${COMMIT}/poc.py`)),
savedFile(rawFile('%2e%2E/poc.py')),
savedFile(rawFile('./poc.py')),
savedFile(rawFile('src//poc.py')),
savedFile(rawFile('poc.py?token=1')),
savedFile(rawFile('poc.py#L1')),
savedFile(`http://raw.githubusercontent.com/owner/poc/${COMMIT}/poc.py`),
savedFile(`https://raw.githubusercontent.com.example/owner/poc/${COMMIT}/poc.py`),
savedFile(`https://gist.githubusercontent.com/owner/poc/raw/${COMMIT}/poc.py`),
savedFile(`https://github.com/owner/poc/blob/${COMMIT}/poc.py`),
savedFile(`https://example.com/owner/poc/${COMMIT}/poc.py`),
savedFile('https://hackerone.com/reports/123456.json'),
// An archive link is never saved again.
savedFile(good.url),
{ ...good, url: savedFile(rawFile('other.py')).url },
{ ...good, url: `https://web.archive.org/web/${stamp}/https://example.com/owner/poc/${COMMIT}/poc.py` },
{ ...good, timestamp: '20261022161014' },
{ ...good, timestamp: Number(stamp) },
{ ...good, url: `https://web.archive.org/web/${stamp}id_/${good.original}` },
{ ...good, url: `https://web.archive.org/web/*/${good.original}` },
{ ...good, url: `http://web.archive.org/web/${stamp}/${good.original}` },
{ ...good, url: `https://web.archive.org/web/20250230093000/${good.original}`, timestamp: '20250230093000' },
{ url: good.url, timestamp: stamp },
good.url, null, [good]
]) {
assert.equal(disclosed(repo, [file]), '', JSON.stringify(file));
}
for (const files of [good, 'files', null, {}]) assert.equal(disclosed(repo, files), '', JSON.stringify(files));
// Advisories, gists, other hosts and files themselves hold no repository files.
for (const parent of ['https://github.com/owner/poc/security/advisories/GHSA-1234-5678-9abc', 'https://gist.github.com/owner/0123',
'https://example.com/owner/poc', good.original]) {
assert.equal(disclosed(parent, [good]), '', parent);
}
// A HackerOne report holds its own report JSON and nothing else.
const json = savedFile('https://hackerone.com/reports/123456.json');
for (const parent of ['https://hackerone.com/reports/123456', 'https://www.hackerone.com/reports/123456/',
'https://hackerone.com/reports/123456?subject=x']) {
assert.match(disclosed(parent, [json]), /1 file<\/summary>/, parent);
}
for (const [parent, file] of [
['https://hackerone.com/reports/123456', savedFile('https://hackerone.com/reports/654321.json')],
['https://hackerone.com/reports/123456', savedFile('https://hackerone.example/reports/123456.json')],
['https://hackerone.com/reports/123456', savedFile('https://hackerone.com/reports/123456')],
['https://hackerone.com/reports/123456', savedFile('https://hackerone.com/reports/123456.json?x=1')],
['https://hackerone.com/reports/123456', good],
['https://hackerone.com/reports/123456.json', json],
['https://hackerone.com/bugs?report_id=123456', json],
['https://example.com/reports/123456', json]
]) {
assert.equal(disclosed(parent, [file]), '', `${parent} ${JSON.stringify(file)}`);
}
});
test('saved file names, links and labels are escaped', async t => {
const { context } = startPage(t, { trending: new Promise(() => {}) });
await new Promise(setImmediate);
const repo = 'https://github.com/owner/poc';
const odd = savedFile(rawFile("x%22%3E%3Cimg%20src%3Dx%20onerror%3Dalert(1)%3E/it's.py"));
context.record = { files: [odd, savedFile(rawFile('100%.py'))] };
const html = vm.runInContext(`archives = { ${JSON.stringify(repo)}: record }; sourceFiles(${JSON.stringify(repo)}, '<b>"label"</b>')`, context);
assert.ok(html.includes(`<a href="${odd.url.replace("'", '&#39;')}" target="_blank"`));
assert.ok(html.includes('aria-label="x&quot;&gt;&lt;img src=x onerror=alert(1)&gt;/it&#39;s.py at commit 0123456 of ' +
'&lt;b&gt;&quot;label&quot;&lt;/b&gt;, Wayback Machine capture 2026-10-22 16:10 UTC">' +
'x&quot;&gt;&lt;img src=x onerror=alert(1)&gt;/it&#39;s.py</a>'));
assert.ok(html.includes('aria-label="2 files saved from &lt;b&gt;&quot;label&quot;&lt;/b&gt;"'));
// A malformed escape is shown as written.
assert.ok(html.includes('>100%.py</a>'));
assert.doesNotMatch(html, /<img|<b>|"label"/);
});
test('an archived fallback discloses its original\'s saved files and no file repeats a row', async t => {
const original = 'https://github.com/owner/gone-poc';
const fallback = `https://web.archive.org/web/20240101120000/${original}`;
const exploit = savedFile(rawFile('exploit.c', 'owner/gone-poc'));
const repo = 'https://github.com/owner/poc';
const listed = savedFile(rawFile('poc.py'));
const helper = savedFile(rawFile('helper.py'));
const entries = [{ cve: 'CVE-2026-1000', desc: 'widget', poc: [fallback, repo, listed.original] }];
const archives = {
[original]: { url: fallback, timestamp: '20240101120000', files: [exploit] },
[repo]: { files: [listed, helper] },
[listed.original]: { url: listed.url, timestamp: listed.timestamp }
};
const { elements } = startPage(t, { search: '?q=widget', entries, archives, trending: new Promise(() => {}) });
await new Promise(setImmediate);
const html = elements.get('[data-results]').innerHTML;
assert.match(html, /3 linked PoCs/);
assert.ok(html.includes('<div class="poc-archive"><span class="wayback is-archived" title="Wayback Machine page snapshot captured ' +
'2024-01-01 12:00 UTC, linked in place of the original" aria-hidden="true">ARCHIVED</span>' +
`<details class="sources" style="--files:1" data-sources="${fallback}"><summary`));
assert.ok(html.includes(`<a href="${exploit.url}" target="_blank" rel="nofollow noopener" ` +
'title="Wayback Machine capture of exploit.c at commit 0123456, 2026-10-22 16:10 UTC" ' +
'aria-label="exploit.c at commit 0123456 of owner/gone-poc, Wayback Machine capture 2026-10-22 16:10 UTC">exploit.c</a>'));
// The lost original is never linked, and no capture is looked up again.
assert.ok(!html.includes(`href="${original}"`));
assert.doesNotMatch(html, /\/web\/\*\/https:\/\/(?:web\.archive\.org|raw\.githubusercontent\.com)/);
// poc.py has a row and a snapshot of its own, so its page discloses only helper.py.
assert.ok(html.includes('aria-label="1 file saved from owner/poc">1 file</summary>'));
assert.ok(html.includes(`<a href="${helper.url}"`));
assert.ok(html.includes(`<a class="wayback is-snapshot" href="${listed.url}"`));
assert.equal(html.split(`href="${listed.url}"`).length, 2);
});
test('an open saved-files list stays open while results re-render', async t => {
const repo = 'https://github.com/owner/poc';
const entries = [{ cve: 'CVE-2026-1234', desc: 'widget', poc: [repo] }];
const { context, elements } = startPage(t, { search: '?q=widget', entries, trending: new Promise(() => {}),
archives: { [repo]: { files: [savedFile(rawFile('poc.py'))] } } });
await new Promise(setImmediate);
const results = () => elements.get('[data-results]').innerHTML;
const toggle = (open, matches = true) => vm.runInContext('rememberSources({ target: { matches: () => ' + matches +
`, open: ${open}, dataset: { sources: ${JSON.stringify(repo)} } } }); renderResults(null);`, context);
assert.ok(results().includes(`data-sources="${repo}"><summary`));
toggle(true);
assert.ok(results().includes(`data-sources="${repo}" open><summary`));
// A toggle elsewhere changes nothing.
toggle(false, false);
assert.ok(results().includes(`data-sources="${repo}" open><summary`));
toggle(false);
assert.ok(results().includes(`data-sources="${repo}"><summary`));
});
test('late or failed archive data never blocks search, reorders results or drops snapshots', async t => {
let finishArchives;
const archives = new Promise(resolve => { finishArchives = resolve; });
const entries = ['CVE-2025-1234', 'CVE-2024-1234'].map(cve => ({ cve, desc: 'widget', poc: [`https://github.com/owner/${cve}`] }));
const { context, elements } = startPage(t, { search: '?q=widget', entries, archives, trending: new Promise(() => {}) });
await new Promise(setImmediate);
const results = () => elements.get('[data-results]').innerHTML;
const ids = () => [...results().matchAll(/class="result-id" href="\/([^"]+)"/g)].map(match => match[1]);
assert.deepEqual(ids(), ['CVE-2025-1234', 'CVE-2024-1234']);
assert.equal(results().match(/class="wayback is-lookup"/g).length, 2);
const status = elements.get('[data-status]').textContent;
const original = 'https://github.com/owner/CVE-2024-1234';
const snapshot = `https://web.archive.org/web/20251021093000/${original}`;
const saved = savedFile(rawFile('poc.py', 'owner/CVE-2024-1234'));
finishArchives({ [original]: { url: snapshot, timestamp: '20251021093000', files: [saved] } });
await new Promise(setImmediate);
assert.deepEqual(ids(), ['CVE-2025-1234', 'CVE-2024-1234']);
assert.ok(results().includes(`class="wayback is-snapshot" href="${snapshot}"`));
assert.ok(results().includes(`<a href="${saved.url}"`));
assert.equal(elements.get('[data-status]').textContent, status);
// A refresh whose archive download fails or is unusable keeps the snapshot and saved file shown.
for (const [at, failure] of ['error', 'malformed'].entries()) {
const feed = { generated: `2026-10-21T1${at}:00:00Z`, with_pocs: 2, total_cves: 2, items: [], landed: [] };
context.fetch = async url => {
const file = url.split('?')[0];
if (file === '/archives.json' && failure === 'error') throw new Error('Unavailable');
return { ok: true, json: async () => file === '/trending_poc.json' ? feed : file === '/CVE_list.json' ? entries
: file === '/archives.json' ? [] : {} };
};
assert.equal(await vm.runInContext('refreshData(true)', context), true);
await new Promise(setImmediate);
assert.deepEqual(ids(), ['CVE-2025-1234', 'CVE-2024-1234']);
assert.ok(results().includes(`class="wayback is-snapshot" href="${snapshot}"`), failure);
assert.ok(results().includes(`<a href="${saved.url}"`), failure);
assert.equal(elements.get('[data-notices]').hidden, true);
}
});
test('snapshots and saved files published with the homepage survive a failed archive download', async t => {
const original = 'https://github.com/owner/poc';
const snapshot = `https://web.archive.org/web/20251021093000/${original}`;
const file = savedFile(rawFile('poc.py'));
const name = { getAttribute: () => original };
const row = { querySelector: () => name };
const sources = { getAttribute: attribute => attribute === 'data-sources' ? original : null };
const published = [
{ getAttribute: () => snapshot, closest: selector => selector === '.trend-row' ? row : null },
{ getAttribute: () => file.url, closest: selector => selector === 'details.sources' ? sources : row }
];
const feed = { generated: '2026-10-21T10:00:00Z', with_pocs: 1, total_cves: 1, items: [], landed: [
{ cve: 'CVE-2026-1234', url: original, name: 'poc', stars: 1, released: '2026-10-21T09:00:00Z', page: '/CVE-2026-1234' }] };
const { elements, calls } = startPage(t, { trending: feed, published, archivesError: true });
await new Promise(setImmediate);
assert.ok(calls.includes('/archives.json'));
const rows = elements.get('[data-trend-rows]').innerHTML;
assert.ok(rows.includes('<div class="trend-sub"><a class="trend-detail" href="/CVE-2026-1234">CVE-2026-1234 details</a>' +
`<a class="wayback is-snapshot" href="${snapshot}"`));
assert.ok(rows.includes(`<details class="sources" style="--files:1" data-sources="${original}"><summary`));
assert.ok(rows.includes(`<a href="${file.url}"`));
assert.doesNotMatch(rows, /is-lookup/);
});
test('a stalled trending feed does not block a bookmarked search', async t => {
const { elements, calls } = startPage(t, { search: '?q=widget', trending: new Promise(() => {}) });
await new Promise(setImmediate);