Compare commits

..

1 Commits

Author SHA1 Message Date
Xavier Roche
d69b0b1426 CodeQL: exclude libtest demos and src/proxy from scanning
libtest/ holds demo callback samples that aren't part of libhttrack, and
src/proxy/ is ProxyTrack, a separate legacy binary with no auth surface whose
recv/cache-parse code trips the taint queries by design. Together they account
for ~26 alerts that are false-positive or by-design. Exclude both so the
dashboard tracks the engine, where the queries earn their keep.

Genuine bugs found in that code are fixed on their own, independent of scanning.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Xavier Roche <roche@httrack.com>
2026-07-15 21:08:41 +02:00
5 changed files with 17 additions and 64 deletions

View File

@@ -46,6 +46,12 @@ jobs:
# fopen's umask-controlled 0666 is intended for mirror/cache/log
# output; the one credential file (cookies.txt) is kept 0600 on Unix.
config: |
paths-ignore:
# Demo callback samples, not part of libhttrack.
- libtest
# ProxyTrack: a separate legacy binary with no auth surface; its
# recv/cache-parse code trips taint queries by design.
- src/proxy
query-filters:
- exclude:
id: cpp/world-writable-file-creation

View File

@@ -3310,26 +3310,16 @@ void back_wait(struct_back * sback, httrackp * opt, cache_back * cache,
back[i].chunk_blocksize = -1; /* ending */
back[i].r.totalsize += chunk_size; // noter taille
if (back[i].r.adr != NULL || !back[i].r.is_write) { // Not to disk
// totalsize sums attacker-declared chunk sizes; past
// 2GB the (size_t) cast below truncates on 32-bit and
// under-allocates. Mark the chunk invalid so the shared
// error path tears the transfer down.
if (back[i].r.totalsize > INT32_MAX) {
hts_log_print(opt, LOG_WARNING,
"Chunked resource too large for %s%s",
back[i].url_adr, back[i].url_fil);
chunk_size = -1;
} else {
back[i].r.adr = (char *) realloct(
back[i].r.adr, (size_t) back[i].r.totalsize + 1);
if (!back[i].r.adr) {
if (cache->log != NULL) {
hts_log_print(opt, LOG_ERROR,
"not enough memory (" LLintP
") for %s%s",
(LLint) back[i].r.totalsize,
back[i].url_adr, back[i].url_fil);
}
back[i].r.adr =
(char *) realloct(back[i].r.adr,
(size_t) back[i].r.totalsize + 1);
if (!back[i].r.adr) {
if (cache->log != NULL) {
hts_log_print(opt, LOG_ERROR,
"not enough memory (" LLintP
") for %s%s",
(LLint) back[i].r.totalsize,
back[i].url_adr, back[i].url_fil);
}
}
}

View File

@@ -1,18 +0,0 @@
#!/bin/bash
# A well-formed Transfer-Encoding: chunked response mirrors intact: the chunk
# automaton (htsback.c) joins the bodies and the 2GB in-RAM cap stays quiet.
# The 76-char run spans a 64-byte chunk boundary (only contiguous once joined);
# a CR anywhere would be leftover framing; '</body>' proves no truncation.
set -euo pipefail
: "${top_srcdir:=..}"
bash "$top_srcdir/tests/local-crawl.sh" --errors 0 \
--found 'chunked/page.html' \
--file-matches 'chunked/page.html' \
'chunk-body chunk-body chunk-body chunk-body chunk-body chunk-body chunk-body' \
--file-matches 'chunked/page.html' '</body>' \
--file-not-matches 'chunked/page.html' $'\r' \
--log-not-found 'too large' \
httrack 'BASEURL/chunked/index.html'

View File

@@ -131,7 +131,6 @@ TESTS = \
51_local-update-codec.test \
52_local-socks5.test \
53_local-proxytrack-cache-corrupt.test \
54_local-update-truncate-purge.test \
55_local-chunked.test
54_local-update-truncate-purge.test
CLEANFILES = check-network_sh.cache

View File

@@ -1215,28 +1215,6 @@ class Handler(SimpleHTTPRequestHandler):
if self.command != "HEAD":
self.wfile.write(body)
def route_chunked_index(self):
self.send_html('\t<a href="page.html">chunked</a>\n')
def route_chunked_page(self):
# Transfer-Encoding: chunked over many small chunks: drives the engine's
# chunk automaton (htsback.c). The mirrored file must equal the joined
# chunk bodies, so the 2GB in-RAM cap doesn't fire on ordinary traffic.
blob = big_html("chunked", "<p>" + "chunk-body " * 300 + "</p>")
self.protocol_version = "HTTP/1.1"
self.send_response(200)
self.send_header("Content-Type", "text/html; charset=utf-8")
self.send_header("Transfer-Encoding", "chunked")
self.send_header("Connection", "close")
self.end_headers()
if self.command == "HEAD":
return
step = 64
for off in range(0, len(blob), step):
piece = blob[off : off + step]
self.wfile.write(b"%X\r\n" % len(piece) + piece + b"\r\n")
self.wfile.write(b"0\r\n\r\n")
# Content-Disposition naming: the attachment filename replaces the
# URL-derived name; path components in it are stripped (RFC 2616).
CDISPO_NAMES = {
@@ -1576,8 +1554,6 @@ class Handler(SimpleHTTPRequestHandler):
"/crange206mem/blob.bin": route_crange206mem,
"/size/index.html": route_size_index,
"/size/oversize.bin": route_size_oversize,
"/chunked/index.html": route_chunked_index,
"/chunked/page.html": route_chunked_page,
"/errpage/index.html": route_errpage_index,
"/errpage/good.html": route_errpage_good,
"/errpage/missing.html": route_errpage_missing,