@@ -419,10 +419,10 @@ describe('parseAndValidateSqlExpression', () => {
419419 expect ( result . error ) . toContain ( 'ParamRef' ) ;
420420 } ) ;
421421
422- it ( 'should reject any unrecognized/new node type via allowlist' , async ( ) => {
422+ it ( 'should reject any unrecognized/new node type via allowlist' , ( ) => {
423423 // Craft a fake AST with a node type not in the allowlist
424424 const unknownAst = { SomeNewDangerousNode : { } } ;
425- const result = await validateAst ( unknownAst ) ;
425+ const result = validateAst ( unknownAst ) ;
426426 expect ( result . valid ) . toBe ( false ) ;
427427 expect ( result . error ) . toContain ( 'Disallowed node type "SomeNewDangerousNode"' ) ;
428428 } ) ;
@@ -536,23 +536,57 @@ describe('parseAndValidateSqlExpression', () => {
536536 expect ( result . error ) . toBeDefined ( ) ;
537537 } ) ;
538538 } ) ;
539+
540+ // ─── SQL injection patterns ───────────────────────────────────
541+
542+ describe ( 'SQL injection patterns' , ( ) => {
543+ it ( 'should reject UNION injection' , async ( ) => {
544+ const result = await parseAndValidateSqlExpression (
545+ '1) UNION SELECT secret FROM users --'
546+ ) ;
547+ expect ( result . valid ) . toBe ( false ) ;
548+ } ) ;
549+
550+ it ( 'should reject UNION ALL injection' , async ( ) => {
551+ const result = await parseAndValidateSqlExpression (
552+ '1) UNION ALL SELECT 1 --'
553+ ) ;
554+ expect ( result . valid ) . toBe ( false ) ;
555+ } ) ;
556+
557+ it ( 'should reject FROM clause injection' , async ( ) => {
558+ const result = await parseAndValidateSqlExpression (
559+ '(SELECT 1 FROM pg_shadow)'
560+ ) ;
561+ expect ( result . valid ) . toBe ( false ) ;
562+ expect ( result . error ) . toMatch ( / d i s a l l o w e d S Q L c l a u s e | D i s a l l o w e d n o d e t y p e / i) ;
563+ } ) ;
564+
565+ it ( 'should reject WHERE clause injection' , async ( ) => {
566+ const result = await parseAndValidateSqlExpression (
567+ '(SELECT 1 WHERE true)'
568+ ) ;
569+ expect ( result . valid ) . toBe ( false ) ;
570+ expect ( result . error ) . toMatch ( / d i s a l l o w e d S Q L c l a u s e | D i s a l l o w e d n o d e t y p e / i) ;
571+ } ) ;
572+ } ) ;
539573} ) ;
540574
541575describe ( 'validateAst' , ( ) => {
542- it ( 'should reject null AST' , async ( ) => {
543- const result = await validateAst ( null ) ;
576+ it ( 'should reject null AST' , ( ) => {
577+ const result = validateAst ( null ) ;
544578 expect ( result . valid ) . toBe ( false ) ;
545579 expect ( result . error ) . toBe ( 'AST must be a non-null object' ) ;
546580 } ) ;
547581
548- it ( 'should reject undefined AST' , async ( ) => {
549- const result = await validateAst ( undefined ) ;
582+ it ( 'should reject undefined AST' , ( ) => {
583+ const result = validateAst ( undefined ) ;
550584 expect ( result . valid ) . toBe ( false ) ;
551585 expect ( result . error ) . toBe ( 'AST must be a non-null object' ) ;
552586 } ) ;
553587
554- it ( 'should reject non-object AST' , async ( ) => {
555- const result = await validateAst ( 'string' ) ;
588+ it ( 'should reject non-object AST' , ( ) => {
589+ const result = validateAst ( 'string' ) ;
556590 expect ( result . valid ) . toBe ( false ) ;
557591 expect ( result . error ) . toBe ( 'AST must be a non-null object' ) ;
558592 } ) ;
@@ -561,18 +595,18 @@ describe('validateAst', () => {
561595 const parseResult = await parseAndValidateSqlExpression ( '42' ) ;
562596 expect ( parseResult . valid ) . toBe ( true ) ;
563597
564- const result = await validateAst ( parseResult . ast ) ;
598+ const result = validateAst ( parseResult . ast ) ;
565599 expect ( result . valid ) . toBe ( true ) ;
566600 expect ( result . canonicalText ) . toBe ( '42' ) ;
567601 } ) ;
568602
569- it ( 'should reject AST containing disallowed nodes' , async ( ) => {
603+ it ( 'should reject AST containing disallowed nodes' , ( ) => {
570604 const forbiddenAst = {
571605 ColumnRef : {
572606 fields : [ { String : { sval : 'username' } } ]
573607 }
574608 } ;
575- const result = await validateAst ( forbiddenAst ) ;
609+ const result = validateAst ( forbiddenAst ) ;
576610 expect ( result . valid ) . toBe ( false ) ;
577611 expect ( result . error ) . toContain ( 'Disallowed node type' ) ;
578612 expect ( result . error ) . toContain ( 'ColumnRef' ) ;
@@ -582,7 +616,7 @@ describe('validateAst', () => {
582616 const parseResult = await parseAndValidateSqlExpression ( 'now()' ) ;
583617 expect ( parseResult . valid ) . toBe ( true ) ;
584618
585- const result = await validateAst ( parseResult . ast , {
619+ const result = validateAst ( parseResult . ast , {
586620 allowedFunctions : [ 'gen_random_uuid' ]
587621 } ) ;
588622 expect ( result . valid ) . toBe ( false ) ;
0 commit comments