Skip to content

Security Camera Shipped a GitHub Admin Token: Lessons

A researcher pulled a GitHub admin token from Hanwha camera firmware. Here's how to scan your own artifacts for the same class of leak.

7 min readBeginner

By the end of this walkthrough you’ll have done what one researcher did in a recent disclosure: downloaded a piece of IoT firmware, cracked it open, and grep’d out a live GitHub admin token. Not because you want to attack anyone – but because seeing the exact chain of mistakes that shipped that token is the fastest way to spot the same pattern in your own builds.

A researcher pulled a Hanwha Vision (formerly Samsung Techwin) security camera firmware, ran TruffleHog, and found a GitHub personal access token repeated in about 30 files. The token had admin privileges to hundreds of repositories in their GitHub organization. Hanwha revoked it within 12 hours of the report. Good outcome, awful root cause – and the root cause is the interesting part.

What actually happened with the security camera GitHub admin token

The bug isn’t “someone hardcoded a password.” It’s subtler. The camera’s admin panel is a single-page app built with Vite. Vite has a specific safety rule: only variables prefixed with VITE_ are exposed to your Vite-processed code (per the official Vite env docs). That prefix is the entire seatbelt.

Someone at Hanwha bypassed it – probably by accident. One of the variables was set to the entirety of process.env at build time. Turns out that dumps the whole CI job’s environment into the shipped JavaScript: every env var the CI runner had – Kubernetes service ports, npm config paths, and one GITHUB_NPM_TOKEN starting with ghp_ – got frozen into the bundle that ships to every camera owner.

Think of it as leaving the office and accidentally taking the whole filing cabinet because you meant to grab one folder. The prefix rule protects the front door. The process.env assignment left the back window open.

The three-step reproduction (safely, on your own artifacts)

Do not point this at somebody else’s firmware to hunt for live tokens. The catch is: verification will actually hit GitHub’s API – more on that in the pitfalls section. Use your own build outputs. Here’s the workflow.

Step 1 – Get the artifact open

For a firmware blob, binwalk is the standard first move. In the Hanwha case there was a twist: binwalk flagged an inner fwimage.tgz as encrypted. The passphrase pattern: HTW + the model number – so HTWXNP-9300RW worked for that device (confirmed by the researcher). For your own web builds you skip this entirely – just point the scanner at your dist/ folder.

Step 2 – Run TruffleHog on the filesystem

TruffleHog is the tool the researcher used. It decodes dozens of encodings – base64, zip files, docx, Docker image layers – before scanning for secrets. Install with Homebrew or Docker, then:

trufflehog filesystem ./extracted-firmware/ 
 --results=verified 
 --json > findings.json

That --results=verified flag limits output to credentials confirmed valid by the provider API (documented in Truffle Security’s 2024 scanning guide), which cuts triage noise sharply. Want to see unverified hits too? Use --results=verified,unknown.

Step 3 – Read the JS bundle by hand

Open any minified JS file from the build. Search for process.env, GITHUB_, _TOKEN, AWS_, or the literal string ghp_. If you see an object literal with dozens of keys like KUBERNETES_SERVICE_PORT_HTTPS or npm_config_userconfig, that’s the smoking gun. Nobody puts those in a client bundle on purpose.

Common pitfalls when running this scan

Legal note: TruffleHog’s verification isn’t passive. When it “verifies” a GitHub token, it makes an authenticated API call as that token. Running it against firmware you don’t own can trigger the vendor’s audit logs – and depending on your jurisdiction, could count as unauthorized access. Scan your own artifacts, or ask permission first.

A few other traps before you spend an afternoon on this:

  • The VITE_ prefix bypass: if a developer writes const W = process.env anywhere in source, Vite inlines the entire object at build time – the prefix rule never fires. That’s exactly what happened here. Full explanation in the root cause section above.
  • Only a tiny fraction of shipped builds may contain the leak. The researcher scraped Hanwha’s site, got around 500 firmwares, extracted 62% of them, and only three contained the GitHub token – all the same token. This looks like recent CI drift, not old policy. Your own build could be one deploy away from the same thing.
  • Rotating the token is necessary but not sufficient. Anyone who downloaded the firmware before revocation still has a copy. There’s no recall for shipped bytes.
  • Verified ≠ dangerous, unverified ≠ safe. A revoked token still looks like a token to a regex; an unverified custom secret can still open a private service.

TruffleHog vs. the alternatives

You have options. Here’s the honest breakdown, based on what each tool actually does rather than marketing copy (based on public documentation, as of early 2025):

Tool Live verification? Scans binaries/archives? Best for
TruffleHog Yes – calls provider APIs Yes – base64, zip, docx, Docker layers Firmware, artifacts, post-mortem forensics
gitleaks No (regex only) Git history focus Pre-commit hooks, fast CI checks
GitHub Secret Scanning Yes, for supported partners Only repos on GitHub Catching leaks the moment they land in a repo
Manual grep No Whatever you throw at it Sanity-checking a specific file

Gitleaks would have missed the Hanwha token entirely – it was in a compiled bundle, not a git commit. GitHub’s own scanner didn’t fire because the token lived in firmware shipped to customers, not pushed to a public repo. That’s the gap TruffleHog fills: filesystem scans of built artifacts, not just source history.

Why this particular vendor matters more than you’d think

One detail worth pausing on. Hanwha isn’t a random no-name camera brand. Hanwha Vision, founded as Samsung Techwin, is a video surveillance company and a subsidiary of Hanwha Group – a conglomerate that also builds K9 Thunder self-propelled artillery and the SGR-A1 sentry gun robot.

That doesn’t mean the cameras are backdoored. It does mean the same organization that puts cameras in enterprise lobbies also builds autonomous weapons systems – and the CI pipeline for one of those product lines was misconfigured enough to publish an admin token to hundreds of repos. That’s the story. Not “IoT is bad,” but “the boring build config is the security perimeter, even for companies you’d expect to know better.”

Do this next

Right now, in the next ten minutes: run trufflehog filesystem ./dist --results=verified against your own web app’s build output. Not the source. The built bundle. If you’re using Vite, also grep your bundle for the literal string process.env. If it appears with any value beyond an empty object, you have a leak candidate to investigate.

FAQ

Is it illegal to download a vendor’s firmware and scan it?

Downloading publicly hosted firmware is generally fine. Using a live token you find inside it is not – and TruffleHog will try to authenticate as that token by default. Run with --no-verification if you only want to detect, not touch.

Why didn’t Vite’s VITE_ prefix rule protect Hanwha?

The VITE_ prefix filters what enters import.meta.env. Write const W = process.env in your own source and Vite sees it as a normal JavaScript expression – it inlines the entire environment object without filtering anything. DB passwords, CI tokens, internal hostnames, all of it. The prefix rule is a guardrail on one specific API surface, not a general filter on bundle output. So: Vite warned about the front door. The developer left the back window open by assigning process.env directly, and Vite had no way to know that wasn’t intentional.

How fast do exposed GitHub tokens typically get abused?

Public repos: seconds to minutes. Automated scanners hit new commits almost immediately after push – there are documented cases of tokens being abused within 30 seconds of a public commit. Firmware is a different story. Nobody’s continuously scraping vendor download pages at that speed, which is likely why Hanwha’s token survived long enough for a human researcher to find it manually. The exposure window is longer, but so is the time before anyone notices.