必须先自行 root 电视并开启 Homebrew Channel 的 SSH 服务,项目不提供漏洞利用代码;install.sh 只安装文件,需再运行 oyg harden 才真正加固;webOS 10 以下默认拒绝执行,强制测试模式可能留下无法恢复的状态。

own-your-glass
JulioFerreroMIT活跃维护给已 root 的 LG webOS 电视做隐私加固:关掉麦克风和遥控语音链路、堵住截屏泄露,双栈屏蔽广告与 ACR 遥测端点,拒绝 LG 授权并精简预装应用,改动可逆且开机生效。
Harden a rooted LG webOS TV: neutralise microphones, the remote-mic voice pipeline and the screen-capture leak; block ad/telemetry/ACR endpoints (dual-stack); decline LG consents; hide ad apps; debloat. Reversible + boot-persistent.
ssh root@<tv-ip> 'curl -fsSL https://raw.githubusercontent.com/JulioFerrero/own-your-glass/main/scripts/install-app.sh | sh'需要已 root 的 LG webOS 电视,README 仅在 webOS 10(webOS 25)上验证过;不涉及显存,脚本运行在电视自带的 BusyBox sh 上。
给已 root 的 LG webOS 电视做隐私加固,关掉麦克风、截屏泄露和广告遥测上报
给已 root 的 LG webOS 电视做隐私加固:关掉麦克风和遥控语音链路、堵住截屏泄露,双栈屏蔽广告与 ACR 遥测端点,拒绝 LG 授权并精简预装应用,改动可逆且开机生效。
核心能力
- 用 /dev/null 替换语音输入管线,保留遥控器其他按键
- bind-mount 屏蔽截屏工具并锁定 capture.rgb 文件
- 按域名同时写入 IPv4 和 IPv6 黑洞,堵住 AAAA 查询绕过
- 每次开机强制拒绝 LG 隐私同意项,防止组件更新后静默重开
- 通过厂商 blockedSystemAppList 隐藏广告应用并使其无法启动
容易踩的坑
- v0.8.14最新正式版2026-10-26 · 2026-10-26 01:06 UTC
- v0.8.132026-10-26 · 2026-10-26 00:58 UTC
查看更新说明
- v0.8.122026-10-26 · 2026-10-26 00:29 UTC
查看更新说明
- v0.8.112026-10-25 · 2026-10-25 21:42 UTC
查看更新说明
- v0.8.102026-10-25 · 2026-10-25 21:42 UTC
查看更新说明
用户点评
登录用户的真实使用记录,可按版本和硬件筛选还没有人点评。第一个说出真实体验的人最有价值。
own-your-glass
Harden a rooted LG webOS TV — kill the microphones, stop the screen-capture leak, block the ad/telemetry endpoints, and debloat the services you never asked for.
The name is a reminder: this tool helps you own the glass on your wall, not the vendor's data pipeline. It does not turn the TV into a fortress. It is a best-effort mitigation of the specific leaks found by your own security investigation on your own rooted webOS TV.
Written in POSIX sh so it runs on the BusyBox shell that ships on the device.
The control panel running on the TV (LG OLED, webOS 10.3.2), captured from the device.
The home screen after Home screen: Clean: LG's banner, quick cards and recommendation shelves are gone, the banner area holds the own-your-glass wallpaper, and your apps sit along the bottom. Captured from the device.
Quick start
Once the TV is rooted (Homebrew Channel installed, its SSH server on; see Rooting your TV), one line installs the app:
ssh root@<tv-ip> 'curl -fsSL https://raw.githubusercontent.com/JulioFerrero/own-your-glass/main/scripts/install-app.sh | sh'
The TV downloads the latest release itself, Homebrew Channel checks its sha256 and installs it, and the app opens. From there it is all the remote: press Apply hardening. Any SSH client works, a phone included, and the same line updates the app later. It is not in Homebrew Channel's own store yet.
Older webOS (testing mode). Apply hardening only runs on webOS 10 and newer, the only
version this has been tested on; on anything older it refuses. To test it on an older TV anyway,
add OYG_FORCE_UNSUPPORTED=1 before sh:
ssh root@<tv-ip> 'curl -fsSL https://raw.githubusercontent.com/JulioFerrero/own-your-glass/main/scripts/install-app.sh | OYG_FORCE_UNSUPPORTED=1 sh'
Apply hardening then runs on that TV (the status board shows "testing mode"). Nobody has run it
on webOS 4–9 yet, so use a TV you can afford to reset, and keep the console's output: it is what
tells us what differs. Undo hardening works on any firmware. The same line with
OYG_FORCE_UNSUPPORTED=0 turns testing mode off.
Prefer the command line? Install (on the TV) below covers install.sh,
oyg harden and the full flag set.
Contents
- Quick start
- What it actually does
- Rooting your TV
- Control panel (the TV app)
- Threat model
- Module table
- How it works (the four techniques)
- Install (on the TV)
- Warn-on-risk / opt-in flags
- Limits
- Documentation
- Attribution
- License
- Disclaimer
What it actually does
- Microphones: every ALSA capture endpoint that can hear the room is neutralised (four on this TV). Playback and the internal loopbacks that carry Bluetooth A2DP and WOWCAST soundbar audio are left alone, so wireless audio keeps working.
- Magic Remote mic + speech-to-text: dead. The
voiceinput_hidraw→voiceinput→voiceconductorpipeline is replaced with/dev/null;/dev/hidraw0stays alive so the rest of the remote still works. - Screen-capture leak (
/tmp/capture.rgb, readable by any app): closed./usr/bin/vtCaptureTestSuiteis bind-mounted over/dev/null; the capture file ischattr+immutable. - Ad / telemetry / ACR domains + ThinQ cloud + firmware-update servers: blocked, dual-stack (IPv4
0.0.0.0and IPv6::1per domain, because an IPv4-only sinkhole let AAAA lookups fall through to DNS). - LG consents: force-declined and re-declined every boot (covers the system silently re-accepting them after a component update).
- Ad / ACR / overlay / SDK-example apps: blocked via the vendor's own
blockedSystemAppList/<REGION>.json. A blocked app is not only hidden: nothing can launch it, so the list holds only apps nothing needs. - Unused feature services and telemetry daemons: stopped, including the usage logger (
service-logger), the crash and analytics reporter (rdxd), the LG Channels beacon (dmost), the Alexa adapter (it kept a live session open even with the mic dead), family care and the LAN print server. Casting is left alone: AirPlay, Chromecast, Screen Share (Miracast), DLNA and DIAL keep working. - HbbTV and the phone remote: HbbTV red-button apps (the source of most third-party trackers seen on the wire) are switched off, and the SSAP phone-remote API on port 3001 is closed to the LAN. LG's ad cookie is emptied.
- DNS: every lookup goes through the on-device sinkhole; resolv.conf no longer lists the ISP's server as a fallback. Three LG servers the TV contacts by IP address (update check, remote support) are blackholed too.
- telnetd (unauthenticated root on the LAN): disabled via
/var/luna/preferences/webosbrew_telnet_disabled, which makes webOSbrew'sstartup.shskip thetelnetd -l /bin/shlaunch. - Home screen (opt-in): LG's ad, promotion, tips and sports-alert settings off; the apps LG pushes onto the app bar (Rakuten TV, LG Streaming Week, 8 Ball Pool, any stub) hidden with their quick cards; optionally the wallpaper layout shown above.
Rooting your TV
oyg requires root. Rootability of a webOS TV is firmware-version-specific — what works on one build may be patched on the next. This project does not ship exploit code; find one that matches your model + firmware on the community sites below.
- Compatibility checker: https://cani.rootmy.tv (model + firmware → supported chains).
- Community guide: https://www.webosbrew.org/rooting/ — the official rooting walk-through.
- RootMyTV: https://rootmy.tv — the original
GetMeNowexploit. Patched on many recent models. - DejaVuln autoroot: https://github.com/throwaway96/dejavuln-autoroot — webOS 3.5+. Other common chains:
faultmanager,GetMeNow. - Research / kernel work: https://openlgtv.github.io.
Before you start, uninstall LG's Developer Mode app if it is present. It conflicts with the rooting chain, and its functionality is replaced by Homebrew Channel once you are rooted.
After rooting, Homebrew Channel is installed automatically. In Homebrew Channel → Settings, enable the SSH server. Leave Telnet off — telnetd ships as an unauthenticated root shell on the LAN, and the policy module maintains the flag that keeps it off.
First login, from your computer:
ssh root@<tv-ip> # default password: alpine
ssh-copy-id -i ~/.ssh/id_ed25519.pub root@<tv-ip>
The key lands at /home/root/.ssh/authorized_keys on the TV. Once that file exists, Homebrew Channel stops provisioning the alpine default password on subsequent boots, so do this immediately.
Never flash the kernel, rootfs, or TVService. See https://rootmy.tv/warning. oyg never writes a system partition; it only changes file modes on writable paths, bind-mounts, ip route entries, and service state.
Warnings:
- Rooting affects your warranty. That is between you and LG.
- A factory reset can lose root and may make re-rooting impossible on that unit — re-check
cani.rootmy.tvfor your firmware before doing either. - The webOSbrew update-blocker flag (touched by the
policymodule) protects your root by sinkholing LG's update servers. It also stops LG kernel security patches from arriving. Pick your trade-off.
Control panel (the TV app)
app/ is a webOS app that puts the toolkit on the remote. It carries its own copy of the
toolkit, so installing the app is all a TV needs. The screenshot at the top is the panel on a
real TV.
- Status comes from
scripts/status-fast.sh, one row per subsystem. The focused row's individual checks show underneath. - Apply hardening installs the bundled toolkit to
/var/lib/own-your-glassand runsoyg hardenwith the network flags on (OYG_NETWORK_BLOCK,OYG_NETWORK_STRICT,OYG_NETWORK_IPBLOCK,OYG_DNS_OVERRIDE,OYG_DNS_RESOLVER,OYG_DNS_VARIANT_C),OYG_LAUNCHER=1(LG's ad and promo settings off, pushed apps hidden) andOYG_LAUNCHER_TRIM=1(the Clean home layout). Variant C restarts ConnMan once, so Wi-Fi drops for 7–30 s; the console says when the internet is back. It also turns HbbTV and the SSAP phone remote off and stops the telemetry daemons listed above. That is stricter than a plainoyg harden; see the opt-in flags for what each one can break. - Check again re-reads the status. Undo hardening runs
oyg restore; what it undoes stays undone after a reboot. - DNS blocking — Turn on / Turn off starts or stops the on-device sinkhole (
scripts/dns.sh), and the choice holds across reboots. Turn on also brings Variant C back when Apply put it on. - Home screen — Clean / Stock switches the home to the wallpaper layout shown at the top
(
OYG_LAUNCHER_TRIM=1) or puts LG's layout back (OYG_LAUNCHER_TRIM=0). Clean is kept at every boot. Apply hardening sets Clean, so Stock lasts until the next Apply. - Restore network runs
scripts/recover-network.sh, which puts networking back to stock and works with no connection. - Leaving the app closes it, so it does not sit in memory behind other apps. A job that is still running finishes first; it runs in the background either way.
The Quick start line installs it. To build it yourself instead (developers):
sh scripts/build-app.sh # writes dist/org.ownyourglass.control-<version>.ipk and prints its sha256
python3 -m http.server 8000 --directory dist # serve it on your LAN
# then, in an SSH session on the TV:
luna-send -w 150000 -n 8 -f luna://org.webosbrew.hbchannel.service/install \
'{"id":"org.ownyourglass.control","ipkUrl":"http://<computer-ip>:8000/org.ownyourglass.control-<version>.ipk","ipkHash":"<sha256>","subscribe":true}'
It prints progress until "statusText": "Finished.". If you run it as a one-shot
ssh root@<tv-ip> '…' instead, add </dev/null to the luna-send line; without a closed stdin
it exits silently and installs nothing.
Rebuild and reinstall the app whenever the toolkit changes: Apply hardening installs the copy the app carries, so an old app puts old code back.
The icon is a three.js render; design/icon/build.sh regenerates app/icon.png,
app/largeIcon.png and the logo at the top of this page.
Threat model
You own the device, it is rooted, but the vendor's data-collection processes (ACR, content miner, object detection, ad overlay, telemetry beacons, voice transcription, screen capture into app sandboxes, RemoteOne remote-support gate, world-writable vendor service code paths) keep running in the background and leak data to LG / cloud / AdTech. This toolkit stops what it can, blocks what it can, and clearly documents what it cannot.
It is not designed to defend against an attacker with root. Once someone has root they can disable everything in this toolkit. The defender-of-root is firmware integrity and boot-chain validation, which this tool does not touch.
Module table
| Module | Neutralises | Opt-in flag | Reversible? |
|---|---|---|---|
capture | Screen-capture leak: chattr+immutable on /tmp/capture.rgb; mount --bind /dev/null on /usr/bin/vtCaptureTestSuite (read-only /usr) | none — safe by default | yes (umount + restore mode) |
mic | Physical ALSA capture PCMs (pcmC1D0c, etc.): chmod 000 + mount --bind /dev/null. Playback and internal loopbacks (pcmC0D10c BT A2DP, pcmC0D14c WOWCAST) untouched. | none — safe by default | yes |
voice | Magic Remote mic pipeline: chmod 000 + bind-null on voiceinput_hidraw, voiceinput, voiceconductor. /dev/hidraw0 deliberately untouched (carries every other remote button). | none — safe by default | yes |
logs | Periodic clear of /tmp/var/log/messages and /tmp/app.voice.log (damage limitation). | none — safe by default | yes (stop the watcher) |
remoteone | Verifies /mnt/lg/cmn_data/remoteDebug/ is absent; optionally tightens cmn_data. | OYG_AGGRESSIVE=1 for the chmod step | yes |
policy | Switches HbbTV off (with Do-Not-Track on and the HbbTV device ID off) and the SSAP phone-remote API off: LG's allowMobileDeviceAccess setting plus only_from = 127.0.0.1 on xinetd's port 3001 entry (Job E); bind-mounts /dev/null over LG's ad cookie (Job F). Touches /var/luna/preferences/webosbrew_block_updates (webOSbrew fallback hosts-bind) and webosbrew_telnet_disabled (suppresses telnetd — unauthenticated root on the LAN); force-declines LG consents in all four on-disk consent stores — /var/luna/preferences/eula (Job B) plus the three SDX/ACR-side stores at /mnt/lg/{cmn_data,cache,user}/sdp/eula-service/eula.json (Job C, A→D for every S_DPA/S_SVC/S_VNG/S_MKT/S_ADG/S_TAG); moves marketingAllowedDate.json aside so the 2-year "re-allow marketing" toast never fires (Job D). All re-applied every boot. | OYG_TOS_IDS="S_VNG S_TAG" allow-list form (default = decline ALL — applies to Job B only); OYG_POLICY_KEEP="hbbTV allowMobileDeviceAccess" leaves Job E settings alone | yes (restore from $OYG_BACKUP/eula.orig + eula-{cmn,cache,user}.orig + marketingAllowedDate.json.orig; Job E settings back to their saved values; mounts undone) |
apps | Blocks a curated list (38 IDs) via the vendor's own blockedSystemAppList/<REGION>.json: ad machinery, remote-support tile, SDK examples, demo apps. A blocked app cannot be launched by anything, so LG's service menu, recovery, diagnostics and upgrade apps are kept off the list (earlier versions blocked them; harden takes them back out). Skips IDs absent on the device. | none — safe by default | yes (restore the original file from backup; without one, take the toolkit's IDs out) |
debloat | Stops + bind-nulls unused feature services and telemetry daemons: mycar, familycare, buddyconnector, alwaysready, ai-inference-manager, avahi-daemon, avahi-adaptor, ruleengine, wowplay, service-logger, rdxd, dmost, ninfod, cups-lpd.socket; bind-nulls /usr/bin/com.webos.app.voice, iconnectivity, uploadd, sportsalarm, amazon-alexa-adapter, performer, nlpmanager, familycare's index.js (dynamic LS2 — bind defeats respawn), plus iot-client when aggressive services are on. Keeps YouTube and LG Channels out of LG's background preload and closes the Alexa overlay LG loads at boot (F51). sdx and ss.gateway are deliberately left alone: neutralising sdx silently breaks the TV's Settings UI (F42), and ss.gateway hosts every JS service, DIAL included (F48). | none — on by default. It does switch features off: LG's WOW wireless-speaker sync for LG soundbars (wowplay), LG phone pairing, family care, AI inference, Alexa, sports alerts and the voice-app UI. AirPlay, Chromecast, Screen Share, DLNA and DIAL are untouched. YouTube opens a moment slower the first time, as it is no longer kept loaded. wowplay stays stopped (Type=static); the rest are stopped again at every boot | yes |
network | Four-layer mitigation: /etc/hosts bind-overlay (dual-stack IPv4+IPv6 sinkhole, always); blackhole public resolvers (always); per-IP blackhole (opt-in); on-device sinkhole resolver on 127.0.0.2:53 hooked in via a /etc/resolv.conf bind-mount (opt-in; the ConnMan route is rejected on this device — see scripts/dns.sh post-mortem). Always blocks LG firmware/update servers; with OYG_NETWORK_STRICT=1 also blackholes three LG servers the TV reaches by hard-coded IP (update check, RemoteOne). | OYG_NETWORK_BLOCK=1 (without it, layer 1 + layer 2 still applied); OYG_NETWORK_STRICT=1; OYG_NETWORK_IPBLOCK=1; OYG_DNS_OVERRIDE=1; OYG_DNS_RESOLVER=1 | yes (umount + route delete + resolv.conf umount) |
launcher | Clean home screen: LG ad / promo / tips / sports-alert settings off (setSystemSettings); pushed apps (every stub, Rakuten TV, LG Streaming Week, 8 Ball Pool) hidden from the app bar with their quick cards (homelaunchpoints); the server-written push list pruned to installed apps; with OYG_LAUNCHER_TRIM=1, the wallpaper layout: a home.xml without quick cards or shelves and with a taller hero, bind-mounted over the original, the wallpaper bind-mounted over the hero's built-in pictures, and the home restarted (all undone automatically if the home's layout parser reports an error). See F45, F50. | OYG_LAUNCHER=1 (opt-in); OYG_LAUNCHER_TRIM=1 for the layout; OYG_LAUNCHER_WALLPAPER=<file>; OYG_LAUNCHER_KEEP="<id> ..." | yes (settings, apps, quick cards, push list, layout and pictures all restored) |
Every module exposes:
mod_<name>_harden— apply, idempotent, reversiblemod_<name>_restore— undomod_<name>_status— printOK|PARTIAL|FAIL|N/A <detail>
oyg verify exits non-zero if any applied module is not in OK or N/A.
How it works (the four techniques)
Everything in this toolkit is built from the same four low-level moves, because a rooted webOS TV gives you very few of them.
mount --bind /dev/nullover a device node or binary (kills the pipe, not the driver).- Over an ALSA PCM like
/dev/snd/pcmC1D0c: everyopen()returnsENXIO/ "Inappropriate ioctl for device" — the kernel still owns the driver, the user-space consumer just cannot read from it. - Over a vendor binary like
/usr/bin/vtCaptureTestSuite(which lives on a read-only/usr, sochmod 000fails): anyexec()reads zeros and fails. Re-launchers hit the bind immediately on the next attempt.
- Over an ALSA PCM like
mount --binda generated file over the read-only/etc/hosts(LG already does this same trick for/etc/shadow).- The network module emits a hosts file from the blocklists at
/var/lib/own-your-glass/hostsand bind-mounts it over/etc/hosts. Dual-stack: every blocked domain gets both0.0.0.0 <d>and::1 <d>— an IPv4-only sinkhole lets AAAA lookups fall through to DNS.
- The network module emits a hosts file from the blocklists at
systemctl stop+ re-stop from an/var/lib/webosbrew/init.dhook.- Because
/etcis a read-only overlay on this device,systemctl maskis impossible (mask writes to/etc/systemd). So the model is: stop now, then stop again on every boot. The init.d hook reads two flat files (services.stopped,services.kill) and re-applies them after the network wait.
- Because
ip route add blackholefor hardcoded public resolvers (because netfilter does not exist on this SoC).iptablesis non-functional (ip_tableskernel module absent),nftis not present,tcreturnsRTNETLINK answers: Operation not supported. The network module's layer 2 blackholes8.8.8.8 / 8.8.4.4 / 1.1.1.1 / 1.0.0.1 / 9.9.9.9 / 208.67.222.222 / 208.67.220.220so daemons that bypass/etc/hostsby talking to a hardcoded resolver IP are still cut.
Install (on the TV)
Supported firmware: webOS 10 (webOS 25). That is the only firmware this toolkit has been run on, and install.sh and oyg harden refuse anything older. On webOS 4 an earlier version half-ran and left a TV that neither oyg restore nor a factory reset could undo (F52, F54). Python is no longer needed: the DNS sinkhole runs on the Node.js every webOS TV ships, JSON is read with BusyBox awk, and the scripts parse and run under the BusyBox 1.24 that webOS 4 is built with. OYG_FORCE_UNSUPPORTED=1 lets an older webOS through, untested; for the app, use the Quick start line's testing mode. oyg restore works on any firmware.
Pick whichever path is easier. (A) runs entirely on the TV; (B) lets you review the repo on your computer first.
(A) One-liner — run ON the TV. The TV's BusyBox + webOS userland ships curl, wget, tar, gzip, and unzip, and can reach GitHub over TLS. After rooting and installing your SSH key:
ssh root@<tv-ip>
curl -fsSL https://github.com/JulioFerrero/own-your-glass/archive/refs/heads/main.tar.gz \
| tar xz -C /tmp \
&& sh /tmp/own-your-glass-main/install.sh
Tarballs from archive/refs/heads/main.tar.gz extract to own-your-glass-main/ — use that exact path. If curl misbehaves, the same flow works with wget:
wget -qO- https://github.com/JulioFerrero/own-your-glass/archive/refs/heads/main.tar.gz \
| tar xz -C /tmp \
&& sh /tmp/own-your-glass-main/install.sh
(B) From your computer — git clone then serve the tree to the TV any way you like (scp to /tmp/own-your-glass and run install.sh there works; the control-panel app does this for you from its bundled copy).
Either path installs to:
/var/lib/own-your-glass/— the toolkit root (state, backups, log, watchers)/var/lib/webosbrew/init.d/oyg— boot hook (re-applies safe modules;run-partsignores dotfiles, so no.shsuffix)
install.sh only copies files and drops the boot hook — nothing is hardened until you run oyg harden below.
After install, inspect what is available, dry-run, apply, then verify:
ssh root@<tv-ip> '/var/lib/own-your-glass/oyg list'
ssh root@<tv-ip> '/var/lib/own-your-glass/oyg harden --dry-run' # review
ssh root@<tv-ip> '/var/lib/own-your-glass/oyg harden' # apply the safe set
ssh root@<tv-ip> '/var/lib/own-your-glass/oyg verify'
Pick your modules (the rest of the flag set is unchanged from before):
# Always safe, no flags:
/var/lib/own-your-glass/oyg harden
# Dry-run first:
/var/lib/own-your-glass/oyg harden --dry-run
# Risky — break ThinQ/Home if applied:
OYG_AGGRESSIVE=1 /var/lib/own-your-glass/oyg harden --only services
OYG_AGGRESSIVE=1 /var/lib/own-your-glass/oyg harden --only perms
# Risky — may break apps/updates:
OYG_NETWORK_BLOCK=1 /var/lib/own-your-glass/oyg harden --only network
# Even riskier — also blocks ThinQ / voice / AI / LG control plane:
# OYG_NETWORK_BLOCK=1 OYG_NETWORK_STRICT=1 /var/lib/own-your-glass/oyg harden --only network
# Also enable per-IP blackhole (layer 3, ages as CDNs rotate):
# OYG_NETWORK_BLOCK=1 OYG_NETWORK_IPBLOCK=1 /var/lib/own-your-glass/oyg harden --only network
# Also rewrite /var/lib/misc/resolv.conf with the default gateway as nameserver:
# OYG_NETWORK_BLOCK=1 OYG_DNS_OVERRIDE=1 /var/lib/own-your-glass/oyg harden --only network
# Recommended — also install the on-device sinkhole resolver and hook it
# in via a /etc/resolv.conf bind-mount (layer 4, closes the connman-bypass
# gap verified on this device — see F14g in docs/FINDINGS.md; the ConnMan
# route itself is rejected, see the post-mortem in scripts/dns.sh):
# OYG_NETWORK_BLOCK=1 OYG_DNS_RESOLVER=1 /var/lib/own-your-glass/oyg harden --only network
# Verify everything is applied:
/var/lib/own-your-glass/oyg verify
Restore everything to the original state:
sh /var/lib/own-your-glass/uninstall.sh
(or /var/lib/own-your-glass/oyg restore if you want to keep the
tool installed but undo the hardening.)
What restore puts back:
- Files (the app block list, the consent stores, the push list, the
marketing schedule) from the copy taken before the first change, with
their original mode. The copy is then kept as
<name>.restored, so a later harden takes a fresh one. - Settings to the values they had, read back from the backup. One that cannot be set back stays in the backup for the next restore.
- Bind mounts and blackhole routes that the toolkit added. Ones that
were there before (webOSbrew's own
/etc/hostsbind, for example) are left alone. - Services it stopped, if they were running before.
- webOSbrew's flags (
webosbrew_block_updates,webosbrew_telnet_disabled) only if they were not there before. A TV hardened by a version before 0.8.12 has no record of that, so restore keeps them and says so; Homebrew Channel's settings turn them off. - DNS: the sink stops, ConnMan gets its stock launcher back if
Variant C was on (Wi-Fi drops for 7–27 s while it restarts), and
/etc/resolv.confis ConnMan's own again.
Not put back: background processes the toolkit killed come back when
the TV next asks for them or at the next boot, and log lines it cleared
stay cleared. oyg restore exits 1 if any module could not be
restored, and uninstall.sh then keeps /var/lib/own-your-glass, with
its backups, instead of deleting it.
Warn-on-risk / opt-in flags
The default oyg harden is conservative. The following flags unlock
risky behaviour. Read the linked findings in docs/FINDINGS.md first.
| Flag | Effect | What can break |
|---|---|---|
OYG_FORCE_UNSUPPORTED=1 | lets install.sh and oyg harden run on a webOS older than 10, which this toolkit has never been run on. The file /var/lib/own-your-glass/allow-unsupported (testing mode, written by the Quick start line with this flag) does the same for the app and the boot hook; OYG_FORCE_UNSUPPORTED=0 overrides it | anything: module paths, app IDs and BusyBox behaviour differ on older firmware |
OYG_AGGRESSIVE=1 (services) | also stops iot-client + pushclient (luna-launched AWS IoT MQTT + LG push channel; systemctl stop is a no-op for the actual process, so the module kills it and re-kills on every boot) | ThinQ app, voice control, push notifications; may be re-spawned on demand by ls-hubd (boot hook is best-effort, not permanent) |
OYG_AGGRESSIVE=1 (perms) | chmods webOSbrew hbchannel + Google Home runtime | webOSbrew updates, Google Home on TV |
OYG_AGGRESSIVE=1 (remoteone) | chmods /mnt/lg/cmn_data from 0777 to 0755 | vendor apps that rely on that directory being world-writable |
OYG_TOS_IDS="S_VNG S_TAG" (policy) | allow-list for the consent-decline step: only the named "id" entries are force-declined; default is decline ALL | depends on which ids you include |
OYG_NETWORK_BLOCK=1 | applies layers 1 + 2 (bind-mount hosts file + blackhole public resolvers) | apps, EPG, SmartShare, firmware updates — anything resolving via libc |
OYG_NETWORK_STRICT=1 | includes the STRICT blocklist section | ThinQ app, voice control, push notifications, LG home-screen card delivery |
OYG_NETWORK_IPBLOCK=1 | also applies layer 3 (per-IP ip route add blackhole) | anything whose IPs happen to be near the listed hosts (CDNs change!) |
OYG_DNS_OVERRIDE=1 | backs up /var/lib/misc/resolv.conf and writes nameserver <default-gw> | any DNS consumer that does NOT honour /etc/hosts (e.g. nslookup, some webOS daemons) |
OYG_DNS_RESOLVER=1 (network, layer 4) | installs an on-device DNS sinkhole resolver (UDP + TCP, scripts/dnssink.js, plain Node.js) and hooks it in via a /etc/resolv.conf bind-mount: the managed file lists only the sink (OYG_DNS_FALLBACK=1 adds the real DHCP-learned upstream as a second nameserver, as older versions did; see F47). The resolver is started and verified answering BEFORE the override goes in; an auto-revert timer (180 s) unmounts an unconfirmed apply. Substring/suffix-match covers subdomains in one rule. Watchdog re-asserts resolv.conf and reverts the override if the resolver dies and won't restart. The bind address comes from $OYG_ROOT/dns.bind (127.0.0.2 by default; 127.0.0.1 under Variant C — see F44). | anything that resolves through /etc/resolv.conf (libc getaddrinfo, most daemons) and nslookup/BusyBox resolution. The ConnMan settings route is rejected on this device: editing connman's settings + nudging connmand (no ExecReload → SIGHUP) took the TV off the network for ~30 min, so this toolkit NEVER signals, reloads or restarts connmand (see the post-mortem in scripts/dns.sh). The launcher-patch route (scripts/go-c.sh, -r --nodnsproxy) is the supported way to close the loopback path: with the sink running, sh /var/lib/own-your-glass/scripts/go-c.sh --check shows what it found on the TV and what it would do, and nohup sh /var/lib/own-your-glass/scripts/go-c.sh </dev/null & does it (it restarts connmand once, with a 660 s rollback armed; scripts/rollback-c.sh undoes it). Worst-case rollback is umount — the TV falls back to ConnMan's own resolv.conf. With the sink as the only nameserver, a dead resolver means failed lookups until the watchdog restarts it or reverts the override (15 s checks). |
OYG_DNS_VARIANT_C=1 (network, with layer 4) | runs scripts/go-c.sh once the sink is up: ConnMan restarts with its own DNS proxy off (-r) and the sink takes over 127.0.0.1:53, so LG's services that ask ConnMan directly go through the blocklist too (F44). Skipped when it is already on. Re-applied at every boot; oyg restore and DNS blocking: Turn off undo it | Wi-Fi drops for 7–30 s each time ConnMan restarts (on, off, and once per boot); a 660 s rollback is armed and cancelled only after the blocked and allowed checks pass |
OYG_LAUNCHER=1 (launcher) | turns LG's ad / promotion / Smart Tips / sports-alert / Live Plus settings off and limit-ad-tracking on, hides the apps LG pushes (stubs, Rakuten TV, LG Streaming Week, 8 Ball Pool) with their quick cards, and prunes the push list | those LG features; Rakuten TV is hidden too (OYG_LAUNCHER_KEEP="ui30" keeps it) |
OYG_LAUNCHER_TRIM=1 (launcher) | also switches the home to the wallpaper layout (quick cards and recommendation shelves removed, the banner area grown into a wallpaper, apps docked below; bind-mounted home.xml and pictures, home restarted); or a list of item IDs to hide instead, e.g. "herobanner qcardList recommendedShelf" for the black minimal layout; 0 puts the stock layout back | the "Recent inputs" and tips rows go with the shelves; use the Live TV tile or the input button instead |
OYG_LAUNCHER_WALLPAPER=<file> (launcher) | uses your own picture for the wallpaper layout (PNG; any size, it is scaled to cover 3492x1450); default goes back to the toolkit's | nothing |
Limits
This is mitigation, not a fortress. In short:
- No firewall. The kernel has no netfilter, so there are no port rules; specific IPs are
blackholed with
ip routeinstead. - No DoH / DoT blocking on the TV. A daemon that resolves over HTTPS (443) or TLS (853) gets past the sinkhole. Block those at your router: see router-level enforcement.
/etcand/usrare read-only, so services are stopped again on every boot rather than masked, and vendor binaries are bind-mounted over rather than edited.- Nothing here stops someone with root, or a firmware update. The kernel, firmware and boot chain are never touched.
- The hardware still hears the room. Neutralising the capture devices makes the audio unreadable to user-space programs; it does not switch the microphones off.
The full list, with how each limit was verified, is in What this CANNOT do on this device.
Documentation
- docs/DOCUMENTATION.md — the reference: each module in depth (network, debloat, apps, launcher,
mic,voice,policy), what the TV cannot do, router-level enforcement, watching the TV's traffic,oyg list, the file layout and boot persistence. - docs/FINDINGS.md — every finding from the investigation, mapped to the module that addresses it and how well.
- docs/VERIFICATION-REPORT.md — the independent verification report on the TV (redacted for publication).
Attribution
This toolkit builds on the work of others. Specific credit:
- Blocklist —
etc/blocklist-upstream-safe.txtis a vendored snapshot of furkan-bayrak/lg-tv-blocklist, retrieved 2026-09-14. The upstream list is licensed CC BY 4.0; attribution to the upstream author is preserved in the file's header. Refresh withscripts/refresh-blocklist.sh(always off-device). - Rooting — webOSbrew / rootmy.tv provide the homebrew channel used to gain the root access this toolkit assumes you already have.
License
This project — code, configuration, and prose — is released under the
MIT License. See the LICENSE file at the repository root.
The vendored blocklist data in etc/blocklist-upstream-safe.txt is a
snapshot of upstream work and remains under its original CC BY 4.0
license; attribution to the upstream author is preserved in the
file's header and must be carried with any redistribution of the
blocklist contents. The NOTICE file says the same and
travels with the app.
Disclaimer
- Never flash the kernel or rootfs. See the upstream rootmy.tv
warning — flashing system partitions can permanently brick the
device. This tool does not flash anything and never writes a system
partition; it only bind-mounts over user-writable paths (or vendor
paths that
mount --bindcan legally target) and stops processes. - Everything is reversible.
oyg restore(oruninstall.sh) puts back what the toolkit changed, and only that; see what restore puts back. - For hardware you own. Root access and OS-level hardening are legitimate on a device you own, but may void your warranty and may violate terms of service in your jurisdiction. Run at your own risk.
- Not a root-level defence. Anyone with root on the device can undo every change here in seconds. The defender-of-root is firmware integrity and boot-chain validation, which this tool does not touch.