ruvnet/ruflo · error
Section " " has negative offset or size
Error message
Section "${sec.id}" has negative offset or size What it means
During fromBuffer's per-section bounds pass, a section in the parsed header declared a negative offset or negative size. Offsets/sizes are unsigned quantities by contract; validateHeader only checks they are numbers, so this loop is the explicit sanity gate before any subarray call. A negative value means the header was deliberately malformed (integer-overflow/underflow style payload) or randomly corrupted.
Solutions
- Do not retry or 'fix' the image — a negative offset/size means the header is malformed or malicious; discard the file and re-fetch from a trusted source
- Verify the image out-of-band: the 32-byte footer hash and detached Ed25519 signature (rvfa-signing.ts) should be checked before parsing untrusted images
- If it's your own writer, audit addSection/build for anything that could compute a negative offset (e.g. subtracting a larger padding from a smaller base)
- Add a pre-parse rejection for untrusted inputs using the signing verification APIs before RvfaReader.fromBuffer
Example fix
// before — parse untrusted bytes directly
const reader = await RvfaReader.fromFile(untrustedPath);
// after — verify signature first, then parse
const ok = await verifyFile(untrustedPath, trustedPublicKey);
if (!ok) throw new Error('image signature invalid — refusing to parse');
const reader = await RvfaReader.fromFile(untrustedPath); Defensive patterns
Strategy: validation
Validate before calling
const parsed = JSON.parse(buf.subarray(12, 12 + buf.readUInt32LE(8)).toString('utf8'));
const sane = (parsed.sections ?? []).every(
(s: any) => Number.isInteger(s?.offset) && s.offset >= 0 &&
Number.isInteger(s?.size) && s.size >= 0,
);
if (!sane) throw new Error('malformed section table — treat as tampered'); Type guard
function hasSaneSections(h: unknown): h is { sections: Array<{ offset: number; size: number }> } {
if (typeof h !== 'object' || h === null || !Array.isArray((h as any).sections)) return false;
return (h as any).sections.every(
(s: any) => Number.isInteger(s?.offset) && s.offset >= 0 &&
Number.isInteger(s?.size) && s.size >= 0,
);
} Try / catch
try { reader = RvfaReader.fromBuffer(buf); }
catch (e) {
if (/negative offset or size/.test(String((e as Error).message))) {
// tamper signal: quarantine the file, alert — do not retry
}
throw e;
} Prevention
- Verify the detached signature before parsing any image from untrusted sources
- Never hand-edit section offsets; rebuild with RvfaWriter instead
- Treat negative offsets/sizes as a security event, not a data glitch
When it happens
Trigger: RvfaReader.fromBuffer on a hostile or corrupted image where any header.sections[] entry has offset < 0 or size < 0 — e.g. a fuzzed .rvfa downloaded from an untrusted source, or a header crafted to make sec.offset + sec.size overflow/wrap past the buffer-end check that follows.
Common situations: Security testing / fuzzing feeds of appliance images; corrupted headers after bit-rot; untrusted mirrors serving modified images. Note the subsequent check (offset + size > totalSize - 32) can be bypassed with large unsigned values that wrap, so treat this error as a tamper signal, not a fluke.
Related errors
- Sections " " and " " overlap ( + > )
- Buffer too small to contain declared header
- Buffer too small to contain RVFA preamble
- Failed to parse RVFA header JSON
- Invalid RVFA magic: expected "RVFA", got
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/ce131978ee95f895.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/appliance/rvfa-format.ts:358
// Parse header JSON
const headerSlice = buf.subarray(PREAMBLE_SIZE, PREAMBLE_SIZE + headerLen);
let parsed: unknown;
try {
parsed = JSON.parse(headerSlice.toString('utf-8'));
} catch {
throw new Error('Failed to parse RVFA header JSON');
}
if (!validateHeader(parsed)) {
throw new Error('RVFA header failed validation');
}
const header = parsed as RvfaHeader;
// Bounds-check every section offset
const totalSize = buf.length;
for (const sec of header.sections) {
if (sec.offset < 0 || sec.size < 0) {
throw new Error(`Section "${sec.id}" has negative offset or size`);
}
if (sec.offset + sec.size > totalSize - SHA256_SIZE) {
throw new Error(
`Section "${sec.id}" extends beyond buffer ` +
`(offset=${sec.offset}, size=${sec.size}, bufLen=${totalSize})`,
);
}
}
// Check for overlapping sections
const sorted = [...header.sections].sort((a, b) => a.offset - b.offset);
for (let i = 1; i < sorted.length; i++) {
const prev = sorted[i - 1];
const curr = sorted[i];
if (prev.offset + prev.size > curr.offset) {
throw new Error(
`Sections "${prev.id}" and "${curr.id}" overlap ` +
`(${prev.offset}+${prev.size} > ${curr.offset})`,View on GitHub (pinned to fa13ee4ad6)