You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A running list of defects surfaced while building out Gargoyle's test tooling
(vnet simulator, GUI chaos/invariance harness, unit suites) and from live
testing on a GL-MT6000. Each entry has the symptom, root cause, user impact,
and current status.
Scope note: security-sensitive findings (memory-safety issues and
input-injection issues) are intentionally not listed here — those are
handled through a separate, non-public process. This ledger covers
functional, reliability, correctness, UX, and build defects only.
Severity is by user impact (High = outage / data loss / can't complete a
core task; Medium = wrong behaviour or collateral damage; Low = cosmetic or
narrow edge case).
Configuration / Basic page
Router IP field rejects CIDR-form ipaddr — High
Symptom: On the Basic page, the Router IP field loads red/invalid and the
LAN IP can't be changed or saved. Saving from that partial state could leave
the LAN unreachable.
Root cause: OpenWrt 24.10+ stores network.lan.ipaddr in CIDR form
(192.168.1.1/24) as a UCI list. The page loaded the raw value into a
field that validateIP() rejects (the /24 suffix), and the first fix only
handled the scalar-string shape, not the list/array the real device uses.
Impact: Can't change the router's LAN address — a core setup task.
Symptom: The initial-settings page's Save spinner spins indefinitely; the
admin password never saves. Timezone dropdown is also empty.
Root cause: Several pages build a JS array from data files with an awk gsub backslash-escape that relies on GNU awk. The firmware ships only busybox awk, which escapes differently, producing malformed JS — the
inline <script> dies, so the save handler throws before sending the request.
Impact: Can't complete first-boot setup. Affected six .sh pages,
including the internationalised first-boot page.
Status:Fixed (busybox-safe sed+awk escaping); validated through a
full build + human first-boot + simulator run. Note the i18n variant
(firstboot.i18n.sh) had to be fixed separately from the base page.
Save-collateral / multi-tab correctness
These are cases where saving one page silently changed config it shouldn't
have — found with a "save-invariance" harness that asserts what a save must not touch.
WireGuard save wipes manually-added peers — High
Symptom: Any save on the WireGuard page removes peers that were added by
hand (e.g. a road-warrior peer set up over SSH).
Root cause:wireguard.jssaveChanges() deletes all wireguard_wg0
sections and rebuilds peers only from its own managed client list, so any
unmanaged peer is dropped.
Impact: Silent loss of VPN peers; could remove the admin's own remote
access path.
Status:Fix implemented + regression test (preserve unmanaged peer
sections on rebuild); validated in built images. Upstream PR to confirm.
Dynamic DNS save clobbers other pages' settings — Medium
Symptom: Saving the Dynamic DNS page reverts an unrelated change made in
another browser tab (e.g. theme or session-timeout).
Root cause:ddns.jssaveChanges() diffs against an empty container
instead of the loaded original, so it re-emits every key it loaded —
including ~26 global settings — overwriting a concurrent edit.
Impact: Multi-tab / multi-admin edits silently lost. Harmless when the
page is saved in isolation.
Status:Fix implemented + regression test (diff against the loaded
original / scope to the ddns section). Upstream PR to confirm.
Access page drops unmanaged dropbear options — Medium
Symptom: Saving the Access page can drop SSH options it doesn't manage
(e.g. enable, RootPasswordAuth).
Root cause: the dropbear section is rebuilt by removing and recreating it,
which discards options the page doesn't know about.
Impact: Silent loss of SSH configuration.
Status:Fixed + regression test (carry unmanaged options across the
rebuild; second save is idempotent).
Symptom: A stale-form save can revert the captive-portal gateway name set
in another tab.
Root cause: field-specific re-emission on save.
Impact: Narrow multi-tab edge case; no solo-save corruption. (Most other
pages flagged by the same detector turned out benign on ground-truth review.)
Status: Confirmed, low priority. The page also restarts the web server
mid-save, which complicates its own save-verification.
Web UI crashes
Quotas page can throw after certain navigation — Medium
Symptom: Navigating to the Quotas page after certain other pages
throws Cannot read properties of null in the sortable-table init; direct
navigation is fine.
Root cause: a sequence-dependent stale global (TSort_*) leaks across
page loads, so the sort init runs against a null table reference.
Impact: Quotas page errors depending on the navigation path taken.
Status:Open — reproduced and quarantined in the browser-journey test;
needs the exact predecessor page pinned and the global reset. Not yet fixed.
DHCP / networking
DHCP alternate-gateway defects — Medium
Symptom: A cluster of issues in the DHCP alt-gateway option: a list-typed dhcp_option could crash the page on load, lease-time was rewritten on
no-op saves (12h → 720m), and the full-gateway field lacked proper
mask handling and a confirm step.
Known Devices with a static IP crash-loops dnsmasq — High
Symptom: Assigning a static IP to a Known Device crash-loops dnsmasq
(duplicate dhcp-host); DNS and DHCP die LAN-wide (looks like "internet down"
but forwarding/NAT still work).
Root cause: the feature wrote twoconfig host sections with the same
MAC+IP, so dnsmasq emitted duplicate dhcp-host= lines and refused to start.
Impact: Network-wide DNS/DHCP outage from a normal admin action.
nftables bandwidth module vs kernel 6.12 — High (build/boot)
Symptom: On the kernel 6.12 base bump, the bandwidth path risked rootfs
corruption / boot failure.
Root cause: kernel-version-specific netfilter API change in the bandwidth
match module.
Impact: Would affect every target on the new kernel base.
Status:Fixed (restore the removed field + bump the module's max
attribute count); built and booted clean across all three simulator sites in a
full suite run.
Test tooling / simulator coverage gaps
Not product bugs, but defects in the tests that let real bugs through —
recorded because closing them is what makes the ledger above trustworthy.
Simulator seeded the wrong config shape. The Basic-page phase reproduced ipaddr as a scalar string while real devices store a UCI list — so it
passed on code that was broken for the list shape (the CIDR bug above). Fixed:
the phase now seeds the list shape, asserts the list injection, and tests both
shapes; proven to fail on the pre-fix code. Lesson: a hand-seeded test must
seed config in the same shape the real device uses.
Tests injected config below the page JS. Early phases set UCI over SSH or
tested extracted functions, so the browser-JS layer where several bugs lived
never ran. Fixed by adding real-browser journey + save-invariance + chaos
test layers.
Backend-only checks give false confidence. Several page backends serve
fine even when the frontend is broken, so a backend-only assertion passes on
broken firmware. The layers with real teeth are the ones that run the shipped
frontend logic against the value the device actually holds.
Security-sensitive findings are tracked separately and are not included above.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Known issues ledger — bugs found during testing
A running list of defects surfaced while building out Gargoyle's test tooling
(vnet simulator, GUI chaos/invariance harness, unit suites) and from live
testing on a GL-MT6000. Each entry has the symptom, root cause, user impact,
and current status.
Severity is by user impact (High = outage / data loss / can't complete a
core task; Medium = wrong behaviour or collateral damage; Low = cosmetic or
narrow edge case).
Configuration / Basic page
Router IP field rejects CIDR-form ipaddr — High
LAN IP can't be changed or saved. Saving from that partial state could leave
the LAN unreachable.
network.lan.ipaddrin CIDR form(
192.168.1.1/24) as a UCI list. The page loaded the raw value into afield that
validateIP()rejects (the/24suffix), and the first fix onlyhandled the scalar-string shape, not the list/array the real device uses.
shapes; regression-locked in unit tests and vnet phase 33 (which now seeds the
real list shape). Verified live on a GL-MT6000.
First-boot password save spins forever — High
admin password never saves. Timezone dropdown is also empty.
awkgsubbackslash-escape that relies on GNU awk. The firmware ships onlybusybox awk, which escapes differently, producing malformed JS — the
inline
<script>dies, so the save handler throws before sending the request..shpages,including the internationalised first-boot page.
sed+awkescaping); validated through afull build + human first-boot + simulator run. Note the i18n variant
(
firstboot.i18n.sh) had to be fixed separately from the base page.Save-collateral / multi-tab correctness
These are cases where saving one page silently changed config it shouldn't
have — found with a "save-invariance" harness that asserts what a save must
not touch.
WireGuard save wipes manually-added peers — High
hand (e.g. a road-warrior peer set up over SSH).
wireguard.jssaveChanges()deletes allwireguard_wg0sections and rebuilds peers only from its own managed client list, so any
unmanaged peer is dropped.
access path.
sections on rebuild); validated in built images. Upstream PR to confirm.
Dynamic DNS save clobbers other pages' settings — Medium
another browser tab (e.g. theme or session-timeout).
ddns.jssaveChanges()diffs against an empty containerinstead of the loaded original, so it re-emits every key it loaded —
including ~26 global settings — overwriting a concurrent edit.
page is saved in isolation.
original / scope to the ddns section). Upstream PR to confirm.
Access page drops unmanaged dropbear options — Medium
(e.g.
enable,RootPasswordAuth).which discards options the page doesn't know about.
rebuild; second save is idempotent).
Captive Portal gateway-name multi-tab clobber — Low
in another tab.
pages flagged by the same detector turned out benign on ground-truth review.)
mid-save, which complicates its own save-verification.
Web UI crashes
Quotas page can throw after certain navigation — Medium
throws
Cannot read properties of nullin the sortable-table init; directnavigation is fine.
TSort_*) leaks acrosspage loads, so the sort init runs against a null table reference.
needs the exact predecessor page pinned and the global reset. Not yet fixed.
DHCP / networking
DHCP alternate-gateway defects — Medium
dhcp_optioncould crash the page on load, lease-time was rewritten onno-op saves (
12h→720m), and the full-gateway field lacked propermask handling and a confirm step.
rewrite, missing confirm-on-enable.
proves bypassed traffic is genuinely uncounted.
Known Devices with a static IP crash-loops dnsmasq — High
(
duplicate dhcp-host); DNS and DHCP die LAN-wide (looks like "internet down"but forwarding/NAT still work).
config hostsections with the sameMAC+IP, so dnsmasq emitted duplicate
dhcp-host=lines and refused to start.Groups PR fix: WireGuard save no longer wipes manually-added peers #57).
Build / kernel compatibility
nftables bandwidth module vs kernel 6.12 — High (build/boot)
corruption / boot failure.
match module.
attribute count); built and booted clean across all three simulator sites in a
full suite run.
Test tooling / simulator coverage gaps
Not product bugs, but defects in the tests that let real bugs through —
recorded because closing them is what makes the ledger above trustworthy.
ipaddras a scalar string while real devices store a UCI list — so itpassed on code that was broken for the list shape (the CIDR bug above). Fixed:
the phase now seeds the list shape, asserts the list injection, and tests both
shapes; proven to fail on the pre-fix code. Lesson: a hand-seeded test must
seed config in the same shape the real device uses.
tested extracted functions, so the browser-JS layer where several bugs lived
never ran. Fixed by adding real-browser journey + save-invariance + chaos
test layers.
fine even when the frontend is broken, so a backend-only assertion passes on
broken firmware. The layers with real teeth are the ones that run the shipped
frontend logic against the value the device actually holds.
Security-sensitive findings are tracked separately and are not included above.
All reactions