Skip to content

[RFC] Safety limits#309

Open
bmcase wants to merge 33 commits intow3c:mainfrom
bmcase:safety_limits
Open

[RFC] Safety limits#309
bmcase wants to merge 33 commits intow3c:mainfrom
bmcase:safety_limits

Conversation

@bmcase
Copy link
Contributor

@bmcase bmcase commented Nov 12, 2025

Creating a PR to add safety limits to the Attribution spec. This is based primarily on the BigBird algorithm from Section 4 of this paper https://arxiv.org/pdf/2506.05290. Algorithm 2 is the main algorithm that encompass both budget deduction and safety limit deduction.

This PR is still WIP but ready for some initial review.

Intended to address this open issue #237


Preview | Diff

This adds the checks that need to happen on user action context, following Alg 2 of BigBird; not that it follows the latest version which has conversion check moved within the for loop over epochs.
in Algo 2 in Big Bird, safety limit deductions occur if and only if privacy budget also happens.
Thus going to put the safety limits into the deduct privacy budget function (renamed as deduct privacy and safety budgets).
@bmcase bmcase changed the title [WIP] Safety limits [RFC] Safety limits Dec 5, 2025
@bmcase
Copy link
Contributor Author

bmcase commented Dec 5, 2025

User actions quota counts -- for the spec I think we should stick closely to the paper on the safety limit quotas themselves, but for the user action quota counts I think we could do a simplification.

The paper partitions the quota counts for a single user action by impression and conversion quotas with conversion quotas further partitioned by epoch.

I think it would be simpler to just have one single quota count per user action. If we think that is okay for now I can simplify this PR a bit.

Let me know if you have any thoughts on this @apasel422 @mt @csharrison @andyleiserson.

mdmostakmia433-sys

This comment was marked as spam.

@mdmostakmia433-sys

This comment was marked as spam.

@bmcase
Copy link
Contributor Author

bmcase commented Dec 11, 2025

Notes from meeting:

  1. drop user action stores by many dimensions
  2. drop conversion site quota

Follow ups:

  1. set minimum recommended multipliers
  2. clear history
  3. locking for atomic transaction

bmcase added 10 commits February 6, 2026 10:06
remove conversion site quota and remove the store of user action contexts, replacing with a global boolean flag attached to the window
create function to calculate deductions for impression sites.
the simpler version was more than lacking optimizations; it would have under deducted in the single epoch but multiple impressions site case.
@bmcase
Copy link
Contributor Author

bmcase commented Feb 10, 2026

@martinthomson Thanks for the review and feedback! I incorporated most of the feedback. I have not yet changed anything related to throwing errors for activation based on user activity as I think we should discuss a few things about this first, see this comment.

Also made sure we have issues tracking these remaining items:

@apasel422 apasel422 requested a review from csharrison February 10, 2026 19:23
incorporate @apasel422 's feedback
@bmcase
Copy link
Contributor Author

bmcase commented Feb 10, 2026

@apasel422 thanks for the review! I think I incorporated all of you feedback

api.bs Outdated
1. If |deduction| is greater than |currentValue|,
[=map/set|set=] the value of |key| in the [=privacy budget store=] to 0
and return false.
1. Let |impressionsBySite| be a new [=map=].
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, this can just be a [=set=] (containing impression sites) as the current PR never reads the map's values.

Copy link
Contributor Author

@bmcase bmcase Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah, you're right we are not using that right now are we. Let me double check on this; I was thinking each source impressions would be used for some optimization in compute impression site deductions but not how it is right now. I'll follow up on this.

Copy link
Contributor Author

@bmcase bmcase Feb 13, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let me remove this for now; but I will open an issue to track something like this as a future optimization. Discussed this with the big bird authors and there is more we have discussed doing here but haven't worked through fully yet. #377

@bmcase
Copy link
Contributor Author

bmcase commented Feb 12, 2026

@martinthomson I updated the user activation check to throw an exception instead of return a boolean, if you want to look anymore at that. Replied on a couple open comment threads.

@apasel422 thanks for the second round of edits; I updated the PR with all of those except one I want to look into more.

adding more prose to describe what we are doing with requiring user activation and some limitations with that.
that could be maliciously triggered.


### Attribution API Activation ### {#s-api-activation}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@martinthomson I added some more explanation to go with this section and links out to the HTML spec. Can you see if this captures what we want to say here?

Copy link
Member

@martinthomson martinthomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not following the whole business of impression quota computation. It might even be wrong. I think that this could be a lot simpler in that area.

Comment on lines +1349 to +1351
The Attribution API requires user activation to prevent abuse. Examples of user activations
that could be used to activate the API include
<a href="https://html.spec.whatwg.org/#user-navigation-involvement">user navigation involvement</a> or clicks on the page.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
The Attribution API requires user activation to prevent abuse. Examples of user activations
that could be used to activate the API include
<a href="https://html.spec.whatwg.org/#user-navigation-involvement">user navigation involvement</a> or clicks on the page.
The Attribution API is a [=transient activation-consuming API=].

I just spent a bit of time looking into this and unfortunately, we're going to have a problem with the existing definition, so I don't want to get too deep into this text right now, so don't overdo the text here; we'll need to rewrite it all. More detail in an issue that I'll open.

Comment on lines +1360 to +1361
1. Since calling the Attribution API consumes a user activation, the site would no longer have this
particular user activation to use for other APIs (e.g., opening popups).
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thankfully, this problem can be fixed by doing the hard work of doing our own activation tracking, which I think is going to be necessary.

Comment on lines +1379 to +1381
<p class=note>This approach allows a single user action to enable multiple
API invocations within the same session, while still requiring
an initial user gesture to activate the API.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
<p class=note>This approach allows a single user action to enable multiple
API invocations within the same session, while still requiring
an initial user gesture to activate the API.
<p class=note>This approach allows a single user action
to enable multiple API invocations within the same session,
while only making the API available to one site
per [=activation triggering input event|activation=].

Comment on lines +1383 to +1385
<p class=issue>TODO: Define how long the [=global attribution API flag=] remains true
and under what conditions it should be reset (e.g., navigation, page lifecycle events).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we have the issue, and it's not a high priority one, ...

Suggested change
<p class=issue>TODO: Define how long the [=global attribution API flag=] remains true
and under what conditions it should be reset (e.g., navigation, page lifecycle events).


</div>


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change

Comment on lines +1244 to +1245
1. If the [=global privacy budget store=] does not [=map/contain=] |epoch|,
[=map/set=] its value to the [=global budget per epoch=].
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As above, same here.

api.bs Outdated
Comment on lines 1255 to 1256
1. If the [=impression site quota store=] does not [=map/contain=] |impressionQuotaKey|
and |siteDeduction| is greater than the [=impression site quota per epoch=], return false.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix the indent.

Also, the above comments.

in the [=privacy budget store=].
1. Let |epoch| be the [=epoch index=] component of |key|.

1. Let |sensitivity| be |l1Norm| if |l1Norm| is non-null, 2 * |value| otherwise.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bit duplicates the computation you have in the impression store bit. I think we can factor out a "compute privacy budget deduction" process for finding the number.

api.bs Outdated
Comment on lines 1174 to 1188
1. Let |impressionsBySite| be a new [=map=].

1. [=set/iterate|For each=] |impression| in |impressions|:

1. Let |impressionSite| be |impression|'s [=impression/impression site=].

1. If |impressionsBySite| does not [=map/contain=] |impressionSite|,
[=map/set=] |impressionsBySite|\[|impressionSite|] to an empty [=set=].

1. [=set/Append=] |impression| to |impressionsBySite|\[|impressionSite|].

1. Let |isSingleEpoch| be true if |l1Norm| is non-null, false otherwise.

1. Let |impressionSiteDeductions| be the result of [=compute impression site deductions|computing impression site deductions=]
with |impressionsBySite|, |deduction|, |value|, |maxValue|, |epsilon|, and |isSingleEpoch|.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not convinced about the necessity of this bit.

Comment on lines +1193 to +1196
1. Let |budgetAvailable| be the result of [=check for available privacy budget|checking for available privacy budget=]
with |key|, |deduction|, and |impressionSiteDeductions|.

1. If |budgetAvailable| is false, return false.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
1. Let |budgetAvailable| be the result of [=check for available privacy budget|checking for available privacy budget=]
with |key|, |deduction|, and |impressionSiteDeductions|.
1. If |budgetAvailable| is false, return false.
1. If the result of invoking [=check for available privacy budget|checking for available privacy budget=]
with |key|, |deduction|, and |impressionSiteDeductions|
is false, return false.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add global privacy budget and per-impression-site quotas

4 participants