fix(session-aliases): reject array-shaped alias maps

This commit is contained in:
Eneko Ruiz committed 2026-10-17 14:13:48 +02:00
1 parent 76aaa77df6
commit b1668579f6
2 files changed
+8 -19

No files matched your search

+1 -1
View File
@@ -58,7 +58,7 @@ function loadAliases() {
const data = JSON.parse(content);
// Validate structure
if (!data.aliases || typeof data.aliases !== 'object') {
if (!data.aliases || typeof data.aliases !== 'object' || Array.isArray(data.aliases)) {
log('[Aliases] Invalid aliases file structure, resetting');
return getDefaultAliases();
}
+7 -18
View File
@@ -1304,15 +1304,8 @@ function runTests() {
'Persisted title should be null after round-trip through saveAliases/loadAliases');
})) passed++; else failed++;
// ── Round 103: loadAliases with array aliases in JSON (typeof [] === 'object' bypass) ──
console.log('\nRound 103: loadAliases (array aliases — typeof bypass):');
if (test('loadAliases accepts array aliases because typeof [] === "object" passes validation', () => {
// session-aliases.js line 58: `typeof data.aliases !== 'object'` is the guard.
// Arrays are typeof 'object' in JavaScript, so {"aliases": [1,2,3]} passes
// validation. The returned data.aliases is an array, not a plain object.
// Downstream code (Object.keys, Object.entries, bracket access) behaves
// differently on arrays vs objects but doesn't crash — it just produces
// unexpected results like numeric string keys "0", "1", "2".
console.log('\nArray alias maps:');
if (test('recovers an invalid array map without losing newly saved aliases', () => {
resetAliases();
const aliasesPath = aliases.getAliasesPath();
fs.writeFileSync(aliasesPath, JSON.stringify({
@@ -1321,15 +1314,11 @@ function runTests() {
metadata: { totalCount: 3, lastUpdated: new Date().toISOString() }
}));
const data = aliases.loadAliases();
// The array passes the typeof 'object' check and is returned as-is
assert.ok(Array.isArray(data.aliases),
'data.aliases should be an array (typeof [] === "object" bypasses guard)');
assert.strictEqual(data.aliases.length, 3,
'Array should have 3 elements');
// Object.keys on an array returns ["0", "1", "2"] — numeric index strings
const keys = Object.keys(data.aliases);
assert.deepStrictEqual(keys, ['0', '1', '2'],
'Object.keys of array returns numeric string indices, not named alias keys');
assert.deepStrictEqual(data.aliases, {});
assert.deepStrictEqual(aliases.listAliases(), []);
assert.strictEqual(aliases.setAlias('recovered', '/session/recovered').success, true);
assert.strictEqual(aliases.resolveAlias('recovered').sessionPath, '/session/recovered');
assert.strictEqual(aliases.loadAliases().metadata.totalCount, 1);
})) passed++; else failed++;
// ── Round 104: resolveSessionAlias with path-traversal input (passthrough without validation) ──