If you believe you found a vulnerability, email:
n.chika156@gmail.com
Please do not open a public GitHub issue first.
Include:
- affected version or commit
- reproduction steps
- impact
- any workaround you already found
- Acknowledgement after the report is received
- Follow-up questions if reproduction details are missing
- A fix or mitigation plan when the report is valid
Response time depends on severity and reproduction quality, but valid reports are handled as priority work.
Security fixes are provided for the latest published release series only.
| Version | Supported | Notes |
|---|---|---|
0.59.x |
Yes | Current published release series as of September 21, 2026 |
0.58.x and earlier |
No | Upgrade to the latest 0.59.x release |
Security fixes are not backported to unsupported release series. When the next series is published, support moves to it.
v1.0.0 has not been published. Work towards it is in main and in the
Unreleased section of CHANGELOG.md; nothing in this table
covers it until there is a tag. Once v1.0.0 is out, support will move to
1.0.x and this table will say so, and from that point the compatibility
promise in the version number is what says whether an upgrade is safe to take.
filesql requires Go 1.26.9 or later. That patch release carries the standard library fixes for
GO-2026-6088 (encoding/xml) and
GO-2026-5972 (encoding/asn1), first
shipped in 1.26.6, and for the net/http advisories GO-2026-6603 and
GO-2026-6611 to GO-2026-6617 that govulncheck finds reachable here. filesql
reaches encoding/xml on every XLSX it reads, so the first of those fixes is on a
path any caller loading a workbook takes. govulncheck runs on every pull
request and on main.
filesql parses file formats. A file from somewhere you do not control is input to a decoder, and the guarantees below are what this project can honestly claim today.
A Parquet page header states how large the page's statistics are. filesql reads
Parquet through parquet-go, and that decoder allocates the declared amount
before reading the bytes, so it never finds out that they are not there. A
damaged 473-byte file therefore allocates about 98 MiB and is then refused. The
refusal is fast — under a millisecond — so this is exhaustion of memory, not of
time, and the cost is paid again on every call: a long-running process opening
the same file twenty times pays it twenty times.
The number sits inside a column chunk rather than in the footer, so filesql never sees it and has nothing to check in front. The footer length, which is the other number a Parquet file declares, is read and bounded before the bytes are handed over.
This was investigated as #526. It is not fixed: the allocation is inside the decoder this project depends on, and forking it or writing an unvetted one of our own would trade a bounded, known cost for an unbounded, unknown one.
Do not point a memory-constrained process at Parquet files you did not
write. Where you must, bound the process rather than the file: a memory limit
on the container or cgroup, or GOMEMLIMIT, turns this into a refused load
rather than a machine under pressure. Checking the file's size first does not
help, since the whole point is that 473 bytes can ask for 98 MiB.
Both formats declare in their header how much working memory the decoder must hold, and a decoder allocates that before reading any data. filesql caps the xz dictionary at 256 MiB and the zstd window at 128 MiB, so a damaged file costs a fixed ceiling rather than whatever its header names. The zstd cap holds for every frame; the xz cap is read from the first block of the first stream, so a later block or a concatenated second stream is not covered by it.
Both formats are parsed by the moov-io libraries, which validate as they read, so a malformed file is refused rather than partly loaded. Neither format is compressed and neither declares a size for filesql to allocate against, so the memory a file costs is bounded by the file.
A Fedwire write-back is verified before it reaches your file: the message is written to a buffer, read back, and compared field by field with the table it was written from. A field that did not survive refuses the whole write, and nothing is written, so a refused export leaves the original where it was. An ACH write-back is not verified the same way, because ACH control records are recalculated by the write and so cannot be compared against what was read.
filesql executes SQL against an in-memory SQLite database. A query string built
by concatenating untrusted text is an injection in filesql exactly as it is
anywhere else; use database/sql placeholders.
OpenReadOnly refuses writes, and it is a guard against writing by accident
rather than a sandbox: it does not confine a caller who sets out to write, and
it says nothing about what a query may read or how long it may run. It is not a
boundary to put untrusted SQL behind.