Summary
lib/plugins/Label_H1_Paren.ts decodes H1 position-report messages of the form (POS-<flight> <lat><lon>/<time> F<alt>\r\nRMK/FUEL <fuel> M<mach>). The outer regex captures the latitude as (?<lat>-?\d{4,5}[NS]) — 4 or 5 digits — but the parseLat helper only understands the 4-digit DDMM form and its inner regex is unanchored, so on a 5-digit input the regex engine slides the match one character to the right and silently returns an out-of-range latitude as the aircraft's position.
Location
lib/plugins/Label_H1_Paren.ts:26,55-62
const regex =
/^\(POS-(?<flight>\w+)\s+(?<lat>-?\d{4,5}[NS])(?<lon>\d{5}[EW])\/(?<timestamp>\d{6})\s+F(?<alt>\d{3})\r?\nRMK\/FUEL\s+(?<fuel>\d{2,3}\.\d)\s+M(?<mach>\d\.\d{2})\)/;
...
function parseLat(latStr: string): number {
const match = latStr.match(/(-?)(\d{2})(\d{2})([NS])/); // <-- unanchored, 2+2 digits only
...
}
Reproduction
const decoder = new MessageDecoder();
const result = decoder.decode({
label: 'H1',
text: '(POS-KLM296 39117N07600W/234212 F250\r\nRMK/FUEL 37.0 M0.69)',
});
console.log(result.raw.position.latitude); // → 91.28333... (invalid latitude, > 90)
Trace inside parseLat('39117N'):
- Inner regex
/(-?)(\d{2})(\d{2})([NS])/ is unanchored.
- At offset 0: consumes
"", 39, 11; next char is 7 (not [NS]) → fails.
- At offset 1: consumes
"", 91, 17; next char is N → matches.
- Returns
sign * (91 + 17/60) = 91.283.
Expected
Either (a) the outer regex should be tightened to \d{4} so the 5-digit form fails the outer match (and decoded: false is returned) — or (b) parseLat should be updated to correctly handle the 5-digit DDMMM (degrees + minutes + tenths-of-minute) form and return 39° 11.7' N ≈ 39.195.
Either way, the current behaviour of emitting 91.283 for a syntactically-accepted input is silent, undetectable-downstream corruption of aircraft position data.
Actual
Silent out-of-range latitude (~91°) reported as the aircraft's position. No error, no fallback — decoded: true and decodeLevel: 'partial' are set.
Recommendation
Anchor and widen the helper, and reject offsets that don't consume the whole capture:
function parseLat(latStr: string): number {
const match = latStr.match(/^(-?)(\d{2})(\d{2}(?:\d)?)([NS])$/);
if (!match) return NaN;
const deg = parseInt(match[2], 10);
const rawMin = match[3];
const min = rawMin.length === 3
? parseInt(rawMin, 10) / 10 // DDMMM → decimal minutes with tenths
: parseInt(rawMin, 10);
const sign = match[4] === 'S' ? -1 : 1;
return sign * (deg + min / 60);
}
The same anchoring smell exists in parseLon — its outer regex fixes the digit count so it's not exploitable today, but the unanchored inner pattern is fragile if the outer regex is ever loosened.
Notes for the reviewer
- Verified that
MessageDecoder.decode() returns whatever the plugin sets; there is no downstream sanity check on latitude ∈ [-90, 90] to catch this.
- No existing test in
Label_H1_Paren.test.ts covers a 5-digit latitude.
Summary
lib/plugins/Label_H1_Paren.tsdecodes H1 position-report messages of the form(POS-<flight> <lat><lon>/<time> F<alt>\r\nRMK/FUEL <fuel> M<mach>). The outer regex captures the latitude as(?<lat>-?\d{4,5}[NS])— 4 or 5 digits — but theparseLathelper only understands the 4-digitDDMMform and its inner regex is unanchored, so on a 5-digit input the regex engine slides the match one character to the right and silently returns an out-of-range latitude as the aircraft's position.Location
lib/plugins/Label_H1_Paren.ts:26,55-62Reproduction
Trace inside
parseLat('39117N'):/(-?)(\d{2})(\d{2})([NS])/is unanchored."",39,11; next char is7(not[NS]) → fails."",91,17; next char isN→ matches.sign * (91 + 17/60)=91.283.Expected
Either (a) the outer regex should be tightened to
\d{4}so the 5-digit form fails the outer match (anddecoded: falseis returned) — or (b)parseLatshould be updated to correctly handle the 5-digitDDMMM(degrees + minutes + tenths-of-minute) form and return39° 11.7' N ≈ 39.195.Either way, the current behaviour of emitting
91.283for a syntactically-accepted input is silent, undetectable-downstream corruption of aircraft position data.Actual
Silent out-of-range latitude (
~91°) reported as the aircraft's position. No error, no fallback —decoded: trueanddecodeLevel: 'partial'are set.Recommendation
Anchor and widen the helper, and reject offsets that don't consume the whole capture:
The same anchoring smell exists in
parseLon— its outer regex fixes the digit count so it's not exploitable today, but the unanchored inner pattern is fragile if the outer regex is ever loosened.Notes for the reviewer
MessageDecoder.decode()returns whatever the plugin sets; there is no downstream sanity check on latitude ∈ [-90, 90] to catch this.Label_H1_Paren.test.tscovers a 5-digit latitude.