This is graffiti on a demo whiteboard, not a master key to the building
CVE-2025-0228 is an XSS bug in code-projects Local Storage Todo App 1.0, specifically js-todo-app/index.html, where the Add input is reflected/executed without proper neutralization. The only affected version publicly identified is 1.0, and the vendor page describes the app as a simple educational HTML/CSS/JavaScript project that runs by opening index.html directly in a browser rather than as a hardened enterprise service.
The vendor's LOW 2.4 score is directionally right, and if anything reality is even less urgent for enterprise defenders. The decisive friction is not the XSS class itself; it is the combination of high privileges required, a toy/demo deployment model, no evidence of in-the-wild abuse, and a blast radius limited to one browser session/localStorage context rather than a central multi-user platform.
4 steps from start to impact.
Find a real deployment worth attacking
- A defender actually deployed
code-projects Local Storage Todo App 1.0 - The app is reachable by the attacker or shared with other users
- This is an educational sample, not a mainstream enterprise product
- Vendor instructions say it runs by opening
index.html, which sharply reduces centralized exposure - Internet-wide exposure is likely negligible compared with normal enterprise web stacks
Get privileged app access
PR:H, so the attacker needs a privileged or admin-capable position inside the app before they can drive the vulnerable Add path as scored by the vendor. That means this is not a clean unauthenticated internet-to-impact story; it already assumes a prior foothold or authorized access in the target context.- Authenticated access with high privileges in the app context
- Requiring high privileges compounds downward pressure on severity
- If an attacker already has admin-level access to a toy todo app, the incremental gain from XSS is small
Inject script into the Add field
Add parameter, which is rendered without safe output encoding. That turns ordinary task content into executable script in the victim browser context.- The vulnerable code path is present in
js-todo-app/index.html - Input reaches a dangerous DOM sink without sanitization
- The bug is limited to one client-side page and one input flow
- Modern browser protections reduce some follow-on abuse, especially if the app has no backend session secrets to steal
Abuse the browser-local impact
- A victim browser renders the malicious content in the vulnerable origin
- No server-side RCE, no database takeover, no broad tenant compromise
- LocalStorage todo data is usually low-value and user-scoped
- Blast radius is usually one origin and one user session
The supporting signals.
| In-the-wild status | No known active exploitation found in authoritative sources reviewed; CISA ADP Vulnrichment marks exploitation as none. |
|---|---|
| KEV status | Not listed in the CISA KEV Catalog. |
| Proof-of-concept availability | Yes, public disclosure/PoC exists. VulDB submission #474049 includes a simple XSS payload example: published by reporter Fergod. |
| EPSS | 0.00093 (~0.093%) per user-provided intel; third-party mirrors place it in a low percentile band and consistent with opportunistic, not prioritized, exploitation. |
| CVSS vector reality check | Vendor vector is CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:U/C:N/I:L/A:N: network reachable in theory, but requires high privileges and user/browser interaction, with only low integrity impact. |
| Affected versions | Only Local Storage Todo App 1.0 is publicly identified in CNA/NVD records. |
| Fixed version | No patched version publicly documented. This looks like a one-off sample project release, not a maintained product stream with versioned security updates. |
| Exposure model | The vendor page says the app runs by opening index.html directly in a browser. That strongly suggests very low enterprise exposure and often no server-side deployment at all. |
| Disclosure timeline | CVE published 2025-01-05; NVD last modified 2025-01-10; VulDB timeline shows advisory disclosure on 2025-01-04. |
| Reporter / source | Reported by Fergod (VulDB User); CNA/assigner is VulDB. |
noisgate verdict.
The single most important severity reducer is deployment reality: this is a niche educational sample app that commonly runs as a local browser file, not a broadly exposed enterprise platform. Even when present, the vendor's own vector requires high privileges, so exploitation usually presupposes access you already should not have.
Why this verdict
- Requires privileged app access: vendor CVSS uses
PR:H, which means this is already post-access and not an unauthenticated edge compromise - Tiny exposed population: the product is an educational HTML/JS sample that the vendor says is run by opening
index.htmlin a browser, so real enterprise deployment is rare - Low blast radius: impact is browser/session/localStorage scoped, with no evidence of server-side code execution, tenant-wide takeover, or infrastructure compromise
Why not higher?
It is not higher because the attack path narrows fast: you need the exact sample app, a real deployment, and privileged access in that app context before the XSS matters. There is also no KEV listing, no campaign reporting, and no sign this sits on a meaningful number of internet-facing enterprise assets.
Why not lower?
It is not pure noise because the underlying bug appears genuine and a public PoC exists. If your developers copied this sample into an internal portal or repackaged it into a shared app, it can still enable session-level browser compromise and content tampering for that specific origin.
What to do — in priority order.
- Document and suppress — If this CVE appears only in vulnerability feeds and you do not knowingly run this sample app, mark it no action required and record the rationale now. For an
IGNOREverdict there is no noisgate mitigation SLA and no remediation SLA; this is governance hygiene, not emergency work. - Hunt for copied sample code — Search dev repos, shared drives, and ad hoc intranet sites for
Local_Storage_Todo_App_In_JS_With_Source_Code,js-todo-app, or the vendor project title. Do this during normal backlog review, because the real risk is not the vendor sample itself but teams copying unsafe front-end patterns into internal apps. - Remove or isolate hobby deployments — If you find a live deployment, retire it or restrict it to a non-production sandbox with no SSO, no sensitive data, and no shared multi-user access. Treat that as routine cleanup rather than security incident response.
- Enforce output encoding and CSP in internal web standards — Use this CVE as a coding-standard reminder: ban unsafe DOM sinks for user content and require a baseline Content Security Policy on internally developed web apps. That reduces recurrence across the broader estate, which matters more than this single sample project.
- Blindly prioritizing by NVD
4.8alone doesn't help; it ignores the admin-only prerequisite and toy deployment model. - Perimeter blocking is mostly irrelevant when the app commonly runs as a local file or intranet page rather than a public service.
- EDR alone will not 'fix' the issue; at best it may catch egregious follow-on browser abuse after script execution.
Crowdsourced verification payload.
Run this on the host or workstation where the app files live, not on a network scanner. Invoke it with python3 check_cve_2025_0228.py /path/to/js-todo-app/index.html; no admin privileges are required, only read access to the file.
#!/usr/bin/env python3
# check_cve_2025_0228.py
# Detects likely vulnerable copies of code-projects Local Storage Todo App 1.0
# Output: VULNERABLE / PATCHED / UNKNOWN
# Exit codes: 0=PATCHED, 1=VULNERABLE, 2=UNKNOWN, 3=usage/error
import os
import re
import sys
from pathlib import Path
DANGEROUS_SINKS = [
r'innerHTML\s*=',
r'insertAdjacentHTML\s*\(',
r'document\.write\s*\(',
r'outerHTML\s*=',
]
APP_MARKERS = [
r'todo',
r'localStorage',
r'add',
]
SAFE_HINTS = [
r'textContent\s*=',
r'createTextNode\s*\(',
r'setAttribute\s*\(\s*["\']text',
]
def usage():
print('UNKNOWN - usage: python3 check_cve_2025_0228.py /path/to/index.html')
sys.exit(3)
def read_file(p: Path):
try:
return p.read_text(encoding='utf-8', errors='ignore')
except Exception as e:
print(f'UNKNOWN - cannot read file: {e}')
sys.exit(2)
def has_any(patterns, text):
return any(re.search(p, text, flags=re.IGNORECASE | re.MULTILINE) for p in patterns)
def main():
if len(sys.argv) != 2:
usage()
target = Path(sys.argv[1])
if not target.exists() or not target.is_file():
print('UNKNOWN - target file does not exist')
sys.exit(2)
if target.name.lower() != 'index.html':
print('UNKNOWN - target is not index.html')
sys.exit(2)
content = read_file(target)
norm = ' '.join(content.split())
app_like = has_any(APP_MARKERS, norm)
dangerous = has_any(DANGEROUS_SINKS, norm)
safe = has_any(SAFE_HINTS, norm)
# Strong path clue from advisory
path_hint = 'js-todo-app' in str(target).replace('\\', '/').lower()
# Heuristic verdicts:
# - VULNERABLE: looks like the sample app and contains unsafe DOM sinks
# - PATCHED: looks like the app and uses safer text sinks without dangerous ones
# - UNKNOWN: anything else
if (app_like or path_hint) and dangerous:
print('VULNERABLE - likely CVE-2025-0228 pattern present (unsafe DOM sink in todo app index.html)')
sys.exit(1)
if (app_like or path_hint) and safe and not dangerous:
print('PATCHED - app markers present, but only safer text insertion patterns found')
sys.exit(0)
print('UNKNOWN - unable to confirm product/version or vulnerable sink pattern')
sys.exit(2)
if __name__ == '__main__':
main()
If you remember one thing.
IGNORE, there is no noisgate mitigation SLA and no noisgate remediation SLA here—document the exception now and spend your patching budget on internet-facing, pre-auth, actively exploited software instead.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.