TC Lab is a lab tool for isolated network testing environments. It is not hardened for internet-facing deployment and by design manipulates the host's live network stack.
| Version | Supported |
|---|---|
| v9.3 (latest) | ✅ |
| v9.2 – v9.2.1 | ✅ — upgrading to v9.3 is recommended (it stops running as root) |
| v9.0 – v9.1 | |
| older | ❌ |
| Area | Before | Now |
|---|---|---|
| Config import | Profile names used as file paths unchecked → arbitrary file write as root | Whole bundle validated (_sanitize_bundle); rejected on any bad name / id |
| Stored XSS | Names rendered into the DOM unescaped | esc() on all kernel/user strings; imported names validated |
| Argument injection | A name could start with - and be read as an ip/tc flag |
Names cannot start with - or .; re-checked in restore_helper.py |
| Look-alike names (v9.2.1) | Some Unicode characters passed validation because the check lower-cased first (the Kelvin sign K became k) |
Names must be plain ASCII |
| CSRF | No tokens | Flask-WTF CSRFProtect; SPA sends X-CSRFToken |
| Cookies | Defaults (no Secure/SameSite); "Keep me signed in" lasted 365 days |
Secure + HttpOnly + SameSite=Strict; 12 h sessions; "Keep me signed in" capped at 7 days (v9.2.1) |
| Login | No brute-force protection, timing oracle, open redirect | 5/min limit, constant-time compare, same-host redirects only (including browser URL-parsing quirks such as /\evil) |
| Headers | None | X-Frame-Options, nosniff, Referrer-Policy, HSTS, CSP |
| Error handling | 500 returned the exception string; import echoed exception text (fixed in v9.2.1) | Generic messages; detail in the log only |
| Deployment | Unconfined systemd root (all 40 capabilities); install owned by the cloning user | Its own unprivileged user, tc-lab, holding only CAP_NET_ADMIN (v9.3); the whole filesystem read-only to it except /var/lib/tc_lab and a private, throwaway /tmp (v9.3); code owned by root; sandboxed unit |
| Management interface (v9.3) | Nothing stopped a VLAN or bridge using it — a bridge wipes its IP address, cutting off access — and such config came back after every reboot | Protected by default (the installer asks): such use is refused. Unprotected, allowed after a warning. Never kept after a reboot either way |
| User management | Hand-edit users.json |
Admin-only dashboard section; tc-lab reset-admin-password for recovery; the state directory, accounts included, is readable only by the service |
| Risk | Severity | Notes |
|---|---|---|
| Network-admin rights on the host | Medium | TC Lab's job is to change the host's interfaces, so the service holds CAP_NET_ADMIN in the host's network. Since v9.3 it runs as its own unprivileged user and can write only /var/lib/tc_lab, so a compromise can no longer edit system files. It could still reconfigure any interface on the host — including the management one — and so disrupt or redirect traffic. It cannot capture packets itself: raw and packet sockets need CAP_NET_RAW, which it no longer has. Getting full root would take a Linux kernel bug, and CAP_NET_ADMIN reaches more of the kernel than an ordinary process does. Keep it on an isolated lab network. |
| Built-in WSGI server | Low–Med | Werkzeug's server (threaded). Fine for a single-operator lab on a trusted network; not for many concurrent users. |
| Self-signed TLS | Low | Encrypts traffic; no identity verification. Import /var/lib/tc_lab/cert.pem as a trusted CA, or drop in your own cert/key. |
| Single-process rate-limit / session store | Low | In-memory; counters reset on restart. Adequate for one instance. |
| "Keep me signed in" has no server-side expiry | Low | The 7-day limit is the cookie's expiry, enforced by the browser; the value is signed, not timed (Flask-Login's design). A copied cookie stays valid until the signing key changes. Leave the box unticked on shared machines; delete /var/lib/tc_lab/secret_key.txt and restart to sign everyone out. |
CSP allows 'unsafe-inline' |
Low | The SPA relies on inline scripts/handlers; CSP still blocks external script/resource loads and framing. |
- Install with
setup.sh, which creates thetc-labservice user and deploys the sandboxed systemd unit. - Set
bind_addressin/var/lib/tc_lab/config.jsonto your management IP; firewall the dashboard port (5000 unless you changed it) to admin workstations only. - Keep the management interface protected (Settings → Management Interface).
- Change the default
admin / tclab123password on first login. - Give day-to-day operators the
userrole; keepadminfor topology and account changes. Create accounts from the dashboard's Users section. - Passwords can only ever be reset, never displayed — including by the CLI.
- Do not expose to the internet under any circumstances.
Please report privately — do not open a public issue. On GitHub, go to the repository's Security tab and choose Report a vulnerability. Only the maintainer can see the report.
Include what you found, how to reproduce it, and the version (tc-lab --version).
Please allow time for a fix before disclosing it publicly.
- Code scanning (CodeQL) runs on every pull request and on
main. Each alert is either fixed or dismissed with a written reason. - Dependabot watches the pinned dependencies in
requirements.txtandrequirements-dev.txtand opens a pull request when one needs a security update.