Commit 1736c84
committed
fix(stream): gate every vhost and refuse CRLF in broker headers
A full security review of the broker, the s6 init scripts, the sudoers
rule and the Dockerfile found two exploitable faults. Both are fixed
here. The third finding, an unset BROKER_SECRET accepting every request,
stays as it is and is now written up in the README as a known debug-only
hole rather than treated as a bug.
The nginx gate covered one vhost. The awk that injects it anchored on
ssl_certificate_key, which appears only in the 3001 SSL server block,
but the base image ships a second, identical plain-HTTP vhost on 3000:
same /websocket proxy to selkies, same /files alias of /config/Desktop.
Anyone reaching port 3000 got the full interactive desktop with the ROM
library mounted and no stream token asked for, and publishing 3000 is
exactly what the base image's own docs tell you to do. Confirmed by
reading /etc/nginx/sites-available/default out of the running container.
The anchor is now every `server {` block. /50x.html is exempted because
it is the error_page target, and a gated error page turns a broker
outage into an internal-redirect loop. The injected port comes from
BROKER_PORT instead of a hardcoded 8000. The script counts the vhosts it
gated, warns when that count is under the two the base image ships, and
reports an ERROR when it matched nothing rather than claiming success.
stream_sid is a Secure cookie, so reaching 3000 directly over plain HTTP
now admits the query token but cannot persist the cookie: 3000 works
behind a TLS-terminating proxy, and unproxied plain HTTP fails closed
instead of serving the desktop.
Two response headers echoed filenames straight to the wire.
X-State-Filename and the save-file Content-Disposition both carry names
taken off the filesystem, where CR and LF are legal bytes, and
http.server writes header values through without validating them. A
state file named with a CRLF could split the response and inject headers
of the attacker's choosing into a browser that fetched it. Both emit
sites now run through a shared _header_token, and PUT /state-file
refuses a non-printable-ASCII filename outright rather than storing a
name it would have to mangle on the way back out.
Hardening applied alongside. The shared secret is compared as bytes,
because hmac.compare_digest refuses a str carrying non-ASCII characters,
so a UTF-8 BROKER_SECRET would have raised inside every check and
answered 500 to every request. The gated vhosts also send
Referrer-Policy: same-origin, so the stream token in the iframe URL does
not leak through a Referer.
Twelve tests cover the new behavior: the header filter, the PUT refusal,
the GET sanitizing a CRLF name already on disk, and the secret
comparison across the UTF-8, ASCII, missing-header and unset-secret
cases.
Deploying this needs a recreate, not a restart. The idempotency check
greps the site config for the marker it already wrote, and /etc/nginx
lives in the container's writable layer, so a restarted container keeps
its single-vhost gate.1 parent 420a2f0 commit 1736c84
4 files changed
Lines changed: 234 additions & 28 deletions
File tree
- root
- etc/s6-overlay/s6-rc.d/init-pcsx2-config
- root
- tests
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
111 | | - | |
| 111 | + | |
112 | 112 | | |
113 | 113 | | |
114 | 114 | | |
| |||
208 | 208 | | |
209 | 209 | | |
210 | 210 | | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
211 | 223 | | |
212 | 224 | | |
213 | 225 | | |
| |||
238 | 250 | | |
239 | 251 | | |
240 | 252 | | |
241 | | - | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
242 | 256 | | |
243 | 257 | | |
244 | 258 | | |
| |||
250 | 264 | | |
251 | 265 | | |
252 | 266 | | |
253 | | - | |
| 267 | + | |
254 | 268 | | |
255 | 269 | | |
256 | 270 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
110 | 110 | | |
111 | 111 | | |
112 | 112 | | |
113 | | - | |
114 | | - | |
115 | | - | |
116 | | - | |
117 | | - | |
118 | | - | |
119 | | - | |
120 | | - | |
121 | | - | |
122 | | - | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
123 | 135 | | |
124 | 136 | | |
125 | 137 | | |
126 | 138 | | |
127 | 139 | | |
128 | | - | |
129 | | - | |
130 | | - | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
131 | 143 | | |
132 | 144 | | |
133 | 145 | | |
134 | 146 | | |
| 147 | + | |
135 | 148 | | |
136 | 149 | | |
137 | 150 | | |
138 | | - | |
| 151 | + | |
139 | 152 | | |
140 | 153 | | |
141 | 154 | | |
142 | 155 | | |
143 | | - | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
144 | 162 | | |
145 | | - | |
146 | | - | |
147 | | - | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
148 | 173 | | |
149 | 174 | | |
150 | 175 | | |
151 | 176 | | |
152 | 177 | | |
153 | | - | |
| 178 | + | |
154 | 179 | | |
155 | 180 | | |
156 | 181 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
29 | 29 | | |
30 | 30 | | |
31 | 31 | | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
32 | 37 | | |
33 | 38 | | |
34 | 39 | | |
| |||
1812 | 1817 | | |
1813 | 1818 | | |
1814 | 1819 | | |
| 1820 | + | |
| 1821 | + | |
| 1822 | + | |
| 1823 | + | |
| 1824 | + | |
| 1825 | + | |
| 1826 | + | |
| 1827 | + | |
| 1828 | + | |
| 1829 | + | |
| 1830 | + | |
| 1831 | + | |
1815 | 1832 | | |
1816 | 1833 | | |
1817 | 1834 | | |
| |||
1820 | 1837 | | |
1821 | 1838 | | |
1822 | 1839 | | |
| 1840 | + | |
| 1841 | + | |
| 1842 | + | |
1823 | 1843 | | |
1824 | | - | |
1825 | | - | |
| 1844 | + | |
| 1845 | + | |
1826 | 1846 | | |
1827 | 1847 | | |
1828 | 1848 | | |
| |||
1967 | 1987 | | |
1968 | 1988 | | |
1969 | 1989 | | |
1970 | | - | |
| 1990 | + | |
| 1991 | + | |
| 1992 | + | |
1971 | 1993 | | |
1972 | 1994 | | |
1973 | 1995 | | |
| |||
1996 | 2018 | | |
1997 | 2019 | | |
1998 | 2020 | | |
1999 | | - | |
2000 | | - | |
2001 | | - | |
| 2021 | + | |
2002 | 2022 | | |
2003 | 2023 | | |
2004 | 2024 | | |
| |||
2155 | 2175 | | |
2156 | 2176 | | |
2157 | 2177 | | |
| 2178 | + | |
| 2179 | + | |
| 2180 | + | |
| 2181 | + | |
| 2182 | + | |
| 2183 | + | |
| 2184 | + | |
2158 | 2185 | | |
2159 | 2186 | | |
2160 | 2187 | | |
| |||
0 commit comments