Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,13 @@ repomix-output.*
private/
# Deploy script - holds server/target details, never shipped.
/scripts/deploy.sh

# --- Syncthing artifacts -------------------------------------
# The whole Khemul folder is synced between machines via Syncthing; never track
# its housekeeping files or conflict copies.
.stfolder/
.stignore
.stversions/
.syncthing.*.tmp
~syncthing~*.tmp
*.sync-conflict-*
15 changes: 14 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.3.1] - 2026-07-24

### Security

- **Bumped `immutable` 5.1.6 -> 5.1.9** to clear two high-severity
denial-of-service advisories (GHSA-v56q-mh7h-f735, GHSA-xvcm-6775-5m9r).
`immutable` is a transitive **dev** dependency pulled in by `sass` and only
runs during the build, never in the shipped app - so the advisories were not
exploitable against users - but this clears the alerts.

### Changed

- **Relicensed from PolyForm Noncommercial 1.0.0 to MIT + Commons Clause.**
Expand All @@ -15,6 +25,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
modification, and free redistribution, and forbid only selling the software
(per the Commons Clause). Updated `LICENSE`, `package.json`, the README badge
and license note, and CONTRIBUTING.
- **Updated dependencies** - `lucide-static` 1.24.0 -> 1.26.0 (Lucide icon set),
plus build and CI tooling (`happy-dom`, `sass`, `actions/checkout`).

## [1.3.0] - 2026-06-25

Expand Down Expand Up @@ -56,5 +68,6 @@ describes the app as it stands at that release.
- **Touch support** - drag to pan, pinch to zoom, and long-press for context
menus on tablets.

[Unreleased]: https://github.com/BrainInBlack/NetGraph/compare/v1.3.0...HEAD
[Unreleased]: https://github.com/BrainInBlack/NetGraph/compare/v1.3.1...HEAD
[1.3.1]: https://github.com/BrainInBlack/NetGraph/compare/v1.3.0...v1.3.1
[1.3.0]: https://github.com/BrainInBlack/NetGraph/releases/tag/v1.3.0
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "netgraph",
"private": true,
"version": "1.3.0",
"version": "1.3.1",
"description": "Browser-based local network visualizer - map your home or lab network, stored entirely in localStorage with no backend.",
"license": "SEE LICENSE IN LICENSE",
"author": "BrainInBlack <braininblack@gmail.com>",
Expand Down
15 changes: 7 additions & 8 deletions src/ts/svg-sanitizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,13 @@ export const MAX_SVG_LENGTH = 64 * 1024;
export function sanitizeSvg(text: string): string | null {
if (text.length > MAX_SVG_LENGTH) return null;

// CodeQL flags this parse as `js/xss-through-dom` ("DOM text reinterpreted as
// HTML"). It is a false positive: this is the sanitizer's own entry point.
// The untrusted string is parsed here, then the tree is scrubbed against an
// allow-list of tags and attributes and walked over all child nodes (dropping
// CDATA, comments, and processing instructions, see the mXSS note below)
// before `root.outerHTML` is returned. Nothing reaches the DOM unsanitized.
// The alert is dismissed as a false positive in GitHub code scanning; keep
// this comment so the reasoning is visible at the source.
// A static analyzer may flag this parse as DOM-based XSS ("DOM text
// reinterpreted as HTML"). It is a false positive: this is the sanitizer's own
// entry point. The untrusted string is parsed here, then the tree is scrubbed
// against an allow-list of tags and attributes and walked over all child nodes
// (dropping CDATA, comments, and processing instructions, see the mXSS note
// below) before `root.outerHTML` is returned. Nothing reaches the DOM
// unsanitized.
const doc = new DOMParser().parseFromString(text, 'image/svg+xml');
const root = doc.querySelector('svg');
if (!root || doc.querySelector('parsererror')) return null;
Expand Down