Skip to content

Commit b62c7a0

Browse files
committed
fix: revoke public trigger privilege on net tables
1 parent 0ab4bae commit b62c7a0

4 files changed

Lines changed: 42 additions & 2 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ else
2626
endif
2727

2828
EXTENSION = pg_net
29-
EXTVERSION = 0.20.3
29+
EXTVERSION = 0.20.4
3030

3131
DATA = $(wildcard sql/*--*.sql)
3232

sql/pg_net--0.20.3--0.20.4.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
revoke trigger on all tables in schema net from PUBLIC;

sql/pg_net.sql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,4 +354,4 @@ $$;
354354

355355
grant usage on schema net to PUBLIC;
356356
grant all on all sequences in schema net to PUBLIC;
357-
grant all on all tables in schema net to PUBLIC;
357+
grant select, insert, update, delete, truncate, references on all tables in schema net to PUBLIC;

test/test_privileges.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,42 @@ def test_net_on_new_role(sess):
120120
set local role postgres;
121121
drop role another;
122122
"""))
123+
124+
125+
def test_public_roles_cannot_create_triggers_on_internal_tables(sess):
126+
"""Internal tables must not allow trigger-based privilege escalation."""
127+
128+
(can_select, can_trigger) = sess.execute(text("""
129+
select
130+
has_table_privilege('pre_existing', 'net._http_response', 'select'),
131+
has_table_privilege('pre_existing', 'net._http_response', 'trigger');
132+
""")).fetchone()
133+
134+
assert can_select is True
135+
assert can_trigger is False
136+
137+
sess.execute(text("""
138+
create table public.t1 (id text);
139+
140+
create or replace function public.my_trigger_fn()
141+
returns trigger
142+
language plpgsql
143+
as $$
144+
begin
145+
insert into public.t1 (id) values (current_user);
146+
return new;
147+
end
148+
$$;
149+
"""))
150+
151+
with pytest.raises(Exception) as execinfo:
152+
sess.execute(text("""
153+
set local role to pre_existing;
154+
155+
create trigger my_trigger
156+
after insert on net._http_response
157+
for each row
158+
execute function public.my_trigger_fn();
159+
"""))
160+
161+
assert "permission denied" in str(execinfo.value)

0 commit comments

Comments
 (0)