fix: some bad requests were not logged

Massimo Melina committed Apr 27, 2026 at 19:27 UTC 33c8335785d0043b1f7a8051ac560a8ab36913c1
3 files changed +22 -2
src/index.ts
+1 -1
@@ -43,7 +43,6 @@ export const app = new Koa({ keys })
43 app.use(sessionMiddleware)
44 .use(selfCheckMiddleware)
45 .use(acmeMiddleware)
46 - .use(someSecurity)
46 .use(prepareState)
47 .use(geoFilter)
48 .use(trackIpsMw)
@@ -52,6 +51,7 @@ app.use(sessionMiddleware)
51 .use(headRequests)
52 .use(rootsMiddleware)
53 .use(logMw)
54 + .use(someSecurity)
55 .use(throttler)
56 .use(pluginsMiddleware)
57 .use(mount(API_URI, apiMiddleware({ ...frontEndApis, ...adminApis })))
src/middlewares.ts
+2 -1
@@ -50,7 +50,6 @@ export const headRequests: Koa.Middleware = async (ctx, next) => {
50 let proxyDetected: undefined | Koa.Context
51 export let cloudflareDetected: undefined | Date
52 export const someSecurity: Koa.Middleware = (ctx, next) => {
53 - ctx.request.ip = normalizeIp(ctx.ip)
53 const ss = ctx.session
54 if (ss?.username && !ss?.[ALLOW_SESSION_IP_CHANGE])
55 if (!ss.ip)
@@ -92,6 +91,8 @@ export function getProxyDetected() {
91 }
92
93 export const prepareState: Koa.Middleware = async (ctx, next) => {
94 + // normalize once so auth, filters and logging agree on the same client address
95 + ctx.request.ip = normalizeIp(ctx.ip)
96 const s = ctx.session
97 if (s?.username) {
98 if (s.ts < invalidateSessionBefore.get(s?.username)!)
tests/test.ts
+19
@@ -1319,6 +1319,25 @@ describe('admin', () => {
1319 })
1320 })
1321
1322 +describe('logging', () => {
1323 + test('security-filtered traversal reaches the error log', async () => {
1324 + const logPath = resolve(__dirname, 'work/logs/access-error.log')
1325 + const uri = `/f1/page/.%2e/.%2e/README.md?log-test=${randomId(8)}`
1326 + const adminJar = {}
1327 + await reqApi('set_config', { values: { dont_log_net: '' } }, 200, { auth, jar: adminJar })()
1328 + try {
1329 + await req(uri, 404, { jar: {} })()
1330 + const found = await waitFor(() =>
1331 + existsSync(logPath) && readFileSync(logPath, 'utf8').includes(uri))
1332 + if (!found)
1333 + throw Error('traversal request was not written to the error log')
1334 + }
1335 + finally {
1336 + await reqApi('set_config', { values: { dont_log_net: '127.0.0.1|::1' } }, 200, { auth, jar: adminJar })()
1337 + }
1338 + })
1339 +})
1340 +
1341 function login(usr: string, pwd=password) {
1342 return srpClientSequence(srp, usr, pwd, (cmd: string, params: any) =>
1343 reqApi(cmd, params, (x,res)=> res.statusCode < 400)())