Repository navigation
Commit 7026141
fix(security)!: an RLS predicate naming an undeclared column denies in every position (#17115)
* fix(security)!: an RLS predicate naming an undeclared column denies in every position
A predicate naming a column the object does not declare could not narrow, and
in a negation-carrying position it did not deny either -- it WIDENED the policy
to every row inside the tenant wall (read face) and PERMITTED the write the
policy was authored to refuse (write face).
Read face: `extractTargetField` is a LEADING `==`/`=`/`in` shape match, so
`nope != "x"`, `!(nope == 1)`, `!(nope in [...])` and any arm after the first
returned `null`, `if (!targetField) return true` KEPT the policy, `dropped`
never incremented and the deny sentinel never armed. Write face:
`computeWriteCheckFilter` compiled `check` clauses with no field-existence net
at all.
The repair is one seam, not two: `RLSCompiler.compileFilter` -- which both the
read layer and the ADR-0058 D4 write gate already pass through -- now takes the
object's declared-column set and judges every column the policy names on the
COMPILED FilterCondition tree. That is positional-agnostic by construction: the
pushdown compiler lowers `!` to `$not`, `||` to `$or` and `&&` to `$and`, so a
column lands as a plain object key whatever position it was authored in, and
there is no spelling of negation left for a shape match to miss.
The matcher's include-direction ruling (`noValueSatisfiesNegation`,
driver-memory / driver-mongodb) is deliberately UNTOUCHED -- it is correct for
an ordinary user query. The defect was that the policy compiler lowered an
undeclared column into a filter at all; the matcher now never sees a phantom.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zTkyNHJ7TkuN2oXtP5x37
* test(security): pin the phantom-column negation shapes on both faces, and correct the linter's consequence prose
The regression suite runs the four negation shapes through the compiler seam
and end-to-end through a real ObjectQL + SecurityPlugin on both SQL drivers,
on the read face and the write face, each against the two controls that make a
reading a reading: a real column must still narrow, and the same phantom column
in a positive position must still refuse. Ablated against the pre-fix source:
36 of 50 cells fail, and the 14 that hold are exactly the controls.
It also pins the include-direction ruling as UNCHANGED -- the raw matcher still
admits 3 of 3 rows for the same filter -- so a later reader can see that what
moved is that the policy compiler stopped producing the filter, not what the
matcher does with one.
The linter's detection is untouched. Its consequence text was stale in one half
and misattributed in the other: it described the field miss as having two
directions decided by position, and it credited the write leg's fail-closed to
a safety net `computeWriteCheckFilter` never had. It now states one direction
for both clauses and records the older runtime's fail-open write behaviour
explicitly.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zTkyNHJ7TkuN2oXtP5x37
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent f89dd33 commit 7026141
6 files changed
Lines changed: 728 additions & 75 deletions
File tree
- .changeset
- packages
- lint/src
- plugins/plugin-security/src
Lines changed: 29 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
Lines changed: 51 additions & 29 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
623 | 623 | | |
624 | 624 | | |
625 | 625 | | |
626 | | - | |
627 | | - | |
628 | | - | |
629 | | - | |
| 626 | + | |
| 627 | + | |
| 628 | + | |
| 629 | + | |
| 630 | + | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
630 | 640 | | |
631 | 641 | | |
632 | 642 | | |
633 | 643 | | |
634 | 644 | | |
635 | 645 | | |
636 | 646 | | |
637 | | - | |
638 | | - | |
| 647 | + | |
| 648 | + | |
639 | 649 | | |
640 | 650 | | |
641 | | - | |
642 | | - | |
643 | | - | |
644 | | - | |
645 | | - | |
646 | | - | |
647 | | - | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
| 658 | + | |
| 659 | + | |
648 | 660 | | |
649 | 661 | | |
650 | 662 | | |
| |||
673 | 685 | | |
674 | 686 | | |
675 | 687 | | |
676 | | - | |
677 | | - | |
678 | | - | |
679 | | - | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
680 | 697 | | |
681 | 698 | | |
682 | 699 | | |
| |||
803 | 820 | | |
804 | 821 | | |
805 | 822 | | |
806 | | - | |
| 823 | + | |
807 | 824 | | |
808 | 825 | | |
809 | 826 | | |
810 | | - | |
| 827 | + | |
811 | 828 | | |
812 | | - | |
813 | | - | |
814 | | - | |
815 | | - | |
816 | | - | |
817 | | - | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
818 | 837 | | |
819 | | - | |
820 | | - | |
821 | | - | |
822 | | - | |
| 838 | + | |
| 839 | + | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
823 | 845 | | |
824 | 846 | | |
825 | 847 | | |
| |||
0 commit comments