Post

Replies

Boosts

Views

Activity

Reply to NEURLFilterManager: inconsistent per-domain blocking (some sites never block, one flaps) - confirmed PIR database is correct
Hello Quinn @DTS Engineer, Thanks for the pointer, I ran the direct NEURLFilter.verdict(for:) call > this confirms the issue is not browser-related at all, and points to something specific in how the verdict is computed. Results (from the SDK header, NEURLFilterVerdictAllow = 2, Deny = 3, Unknown = 1): winamax.fr -> Deny (3) — correct unibet.fr -> Allow (2) — wrong betclic.fr -> Allow (2) — wrong olybet.fr -> Allow (2) — wrong (this is the one that flaps in-browser) fdj.fr -> Deny (3) — correctThis is the key part: it's returning a confident Allow, not Unknown (which would mean the validation itself failed). And I'd already independently proven, by querying our deployed PIR database shards directly (bypassing OHTTP, the app, and the device entirely), that every one of these domains - including unibet.fr and betclic.fr - correctly returns the blocked value in our data. Our local bloom prefilter file is also confirmed byte-correct, with all of these domains properly hashed in. So: the local prefilter data is right, the PIR database is right, yet the on-device verdict computation still returns the wrong answer for these specific domains. That narrows it down to something inside the verdict pipeline itself - bloom-check-to-PIR-query handoff, or PIR response interpretation - rather than any input data I can inspect or fix on my end. Is there anything you can share about how NEURLFilter resolves a verdict internally, or does this look like something worth filing as a bug?
13h
Reply to NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
Quick closing update on this one - tracked it down and fixed it. Root cause: RFC 9458 §4.1 encapsulates requests with context.Seal("", request)the AEAD's additional authenticated data is empty, the header only feeds into info and the wire envelope. Our server was incorrectly using the header as the AEAD's AAD too, causing every real device request to fail authentication while our own (identically wrong) test script kept "succeeding" against it in lockstep, masking the bug for weeks. Fixed and deployed — the filter now shows "Running" on a real device for the first time. Thanks for your help narrowing down the Linux/OpenSSL HPKE issue earlier, that was a necessary step to get here. Closing this thread & and thanks again for the help
1d
Reply to NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
Hi Quinn @DTS Engineer, Just a gentle follow-up It's been somes days since my last message and I haven't found a solution yet on my end either, so wanted to check in. To recap where we're stuck: the manual HPKE reimplementation fixed the platform-specific Linux/OpenSSL CIPHER_R_BAD_DECRYPT issue you helped us trace (confirmed via self-constructed test requests succeeding consistently on both macOS and Linux now). But real requests coming from NEURLFilterManager on a physical iPhone still fail decapsulation with an AEAD authentication failure (HPKE open failed), while our own hand-built RFC 9458 requests against the same server succeed every time. So there's some remaining difference between how the real client constructs its OHTTP request and what we're decrypting on the server side that I haven't been able to identify from the spec alone. I was considering setting up a MITM proxy (mitmproxy) with a trusted root certificate installed on the iPhone, to capture the actual raw OHTTP POST body the device sends to our gateway and compare it byte-for-byte against what our server expects. Before I sink a weekend into that: Does that sound like a reasonable diagnostic approach to you, given NEURLFilterManager/the underlying network extension agent is a system-level component - is it likely to even respect a standard proxy/trust-store configuration, or does it bypass that layer entirely? Is there anything non-standard about how Apple's real OHTTP client builds the request that wouldn't be obvious from RFC 9458/9180 alone - e.g. a different info/aad construction, an intermediate relay reshaping the request, or key rotation/caching behavior on the client side that could cause it to encrypt against a stale key config? Or do you think I'm chasing the wrong thing entirely here, and the real issue is somewhere else (e.g. in how the key config or bloom prefilter is being fetched/cached on-device)? Thanks again for your help on this.
3d
Reply to NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
Hi @DTS Engineer Quinn made real progress based on your BAD_DECRYPT lead, with a new, more specific finding. I bypassed swift-crypto's HPKE.Recipient/HPKE.Sender entirely and implemented RFC 9180 base-mode HPKE manually using the lower-level primitives (Curve25519 key agreement, HKDF, AES-GCM) instead. Confirmed this resolves the platform-specific bug: a standalone HPKE test request I construct now decrypts successfully both locally on macOS and on the actual Fly.io/Linux deployment - identical result on both platforms now, where before it only worked on macOS. However, real requests from the iOS device still fail - now with a cleaner, more specific error: a genuine AEAD authentication failure (HPKE open failed), not the generic library crash from before. So my implementation correctly handles a standard RFC 9180 request, but something about the actual request the device sends doesn't match what I'm computing. Is there anything non-standard about how NEURLFilterManager/the PIR client constructs or routes these OHTTP requests that might not be obvious from the RFC - e.g., does it go through an Apple-operated OHTTP relay that re-encapsulates in transit, or is there a PIR-specific wrinkle in how info/aad are built that differs from generic OHTTP? Trying to figure out what to compare my reimplementation against, since I don't have visibility into the real device's raw request bytes. Thanks again - your BAD_DECRYPT read got us this far.
1w
Reply to NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
@Pushpak-Ambadkar123 hello, yes, I've dug a lot further on this. The full client-side sequence (on-device, Console.app filtered by NEPIRChecker) looks like this before that error: <NEPIRChecker>: -[NEPIRChecker start:responseQueue:completionHandler:] - Register with PIR Server (...) completed registration with PIR for Group ... <NEPIRChecker>: -[NEPIRChecker start:responseQueue:completionHandler:]_block_invoke - PIR status returned error <Error Domain=com.apple.CipherML Code=1100 ...>But the real root cause, if you also run your own PIR server and have access to its logs: on my server side, this traces back to an HPKE decapsulation failure in the OHTTP gateway Crypto.CryptoKitError.underlyingCoreCryptoError(error: 503316581)thrown from HPKE.Recipient(...)/.open(ct, authenticating:) when decrypting the incoming OHTTP request. I confirmed it's reproducible independently of the real client using a standalone HPKE test script, and that the failure rate seems to fluctuate with server uptime (worse after the process has been running a while) - pointing toward a possible concurrency issue around shared key material. Are you running your own PIR server, or hitting this purely from the client side? If you have server logs too, it'd be great to compare notes; might help build an even stronger case for @DTS Engineer Quinn.
1w
Reply to NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
Hi @DTS Engineer Following up with a much more precise finding after digging into server-side logs. The failure is happening in our PIR server's OHTTP gateway, specifically in HPKE request decapsulation: [OHTTP] decapsulateRequest failed: Crypto.CryptoKitError.underlyingCoreCryptoError(error: 503316581)This is thrown from HPKE.Recipient(privateKey:ciphersuite:info:encapsulatedKey:) / .open(ct, authenticating:) (DHKEM(X25519, HKDF-SHA256) / HKDF-SHA256 / AES-128-GCM, per RFC 9458). What I've confirmed: Not an entitlement/config issueThe NEURL Filter configuration is correctly onboarded, and the client reaches this point successfully (handshake, registration all succeed first). Reproducible independently of the iOS client I wrote a standalone Python script using a real HPKE library (pyhpke), fetched our server's published /.well-known/ohttp-gateway key, and built a byte-for-byte RFC 9458-compliant OHTTP request against it. It fails with the exact same CryptoKitError.underlyingCoreCryptoError(error: 503316581). So this isn't specific to anything the iOS client does. Failure rate seems to fluctuate over server uptime Right after restarting the server process, a handful of real device requests briefly succeeded decryption (progressing to a later, unrelated parsing error), then it reverted to failing on essentially every attempt a few minutes later. This pattern makes me suspect a concurrency/thread-safety issue around the shared Curve25519.KeyAgreement.PrivateKey being used to construct a new HPKE.Recipient on every incoming request, rather than a static configuration problem. Any idea what corecrypto error 503316581 typically indicates, or whether there's a known gotcha with concurrent HPKE.Recipient construction from a shared private key in swift-crypto? Happy to share the Python repro script and/or file a bug with logs attached if that would help narrow it down. Thanks again for sticking with this one.
1w
Reply to NEURL Filter configuration approved under wrong Developer Team — resubmission blocked by duplicate domain
Hi @DTS Engineer — quick update now that the account transfer is confirmed onboarded on the good ID (thank you!). Running into a new, separate issue now when actually enabling the filter on device. The extension launches fine, XPC handshake succeeds, and PIR registration completes successfully. But the subsequent NEPIRChecker status check fails every time (retried repeatedly over several minutes, same result each time): PIR status returned error <Error Domain=com.apple.CipherML Code=1100 "Unable to query status due to errors: Error details were logged and redacted." UserInfo={NSLocalizedDescription=Unable to query status due to errors: Error details were logged and redacted., NSUnderlyingError=0x677037cf0 {Error Domain=com.apple.CipherML Code=1800 "Error details were logged and redacted." UserInfo={NSLocalizedDescription=Error details were logged and redacted.}}}>Config being registered (confirmed from the logs): pirServerURL = https://pir.dropbet.app/ pirPrivacyPassIssuerURL = https://pir.dropbet.app/issueBoth endpoints are live and were already validated as part of the original NEURL Filter configuration approval. I've captured a sysdiagnose from the device right when this was happening, so I have that ready to attach to a bug report if useful — just let me know and I'll file one. Any idea what CipherML error 1100/1800 typically indicates? Thanks again for all the help on this.
Topic: Code Signing SubTopic: Entitlements Tags:
1w
Reply to NEURL Filter configuration approved under wrong Developer Team — resubmission blocked by duplicate domain
Hello Quinn, Today I recive the mail about my onboarding : Your configuration [NE URL Filter] 9f3cbff8-63de-4c69-bf68-c19cd1c5d842 has been successfully onboarded and is now active. what´s the next step ? did i have to do something els for the transfer (FB24607828); or i have just to wait ? best regards & thanks again, Romain DropBet
Topic: Code Signing SubTopic: Entitlements Tags:
4w
Reply to NEURL Filter configuration approved under wrong Developer Team — resubmission blocked by duplicate domain
Got it, thanks for clarifying — that makes sense. Is there anything needed from my side for the onboarding step, or is it now entirely on Apple's end? And do you have any rough sense of timeframe (days, weeks, months) I should plan around, even approximate? Just trying to figure out whether to keep waiting or look at alternatives in the meantime.
Topic: Code Signing SubTopic: Entitlements Tags:
Sep ’26
Reply to NEURL Filter configuration approved under wrong Developer Team — resubmission blocked by duplicate domain
Thanks for looking into it, @DTS Engineer Quinn! Just to clarify though — this isn't a new PIR onboarding in progress. The configuration (ID 9f3cbff8-63de-4c69-bf68-c19cd1c5d842) was already fully approved back on Aug 5, so there's no review pending on the PIR server itself. The actual issue is that it's attached to the wrong Apple Developer Team (ex personnel acc Romain Scotto : S5VDH23BBZ instead of the organisation acc SCOTTO : KRKJ76BC7W), and the portal blocks any attempt to fix that with "A configuration with the same PIR Server Domain already exists." So there's nothing to wait out — it's purely a matter of reassigning the existing approved config to the correct team. Does that change things on your end?
Topic: Code Signing SubTopic: Entitlements Tags:
Sep ’26
Reply to NEURLFilterManager: inconsistent per-domain blocking (some sites never block, one flaps) - confirmed PIR database is correct
Hello Quinn @DTS Engineer, Thanks for the pointer, I ran the direct NEURLFilter.verdict(for:) call > this confirms the issue is not browser-related at all, and points to something specific in how the verdict is computed. Results (from the SDK header, NEURLFilterVerdictAllow = 2, Deny = 3, Unknown = 1): winamax.fr -> Deny (3) — correct unibet.fr -> Allow (2) — wrong betclic.fr -> Allow (2) — wrong olybet.fr -> Allow (2) — wrong (this is the one that flaps in-browser) fdj.fr -> Deny (3) — correctThis is the key part: it's returning a confident Allow, not Unknown (which would mean the validation itself failed). And I'd already independently proven, by querying our deployed PIR database shards directly (bypassing OHTTP, the app, and the device entirely), that every one of these domains - including unibet.fr and betclic.fr - correctly returns the blocked value in our data. Our local bloom prefilter file is also confirmed byte-correct, with all of these domains properly hashed in. So: the local prefilter data is right, the PIR database is right, yet the on-device verdict computation still returns the wrong answer for these specific domains. That narrows it down to something inside the verdict pipeline itself - bloom-check-to-PIR-query handoff, or PIR response interpretation - rather than any input data I can inspect or fix on my end. Is there anything you can share about how NEURLFilter resolves a verdict internally, or does this look like something worth filing as a bug?
Replies
Boosts
Views
Activity
13h
Reply to NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
Quick closing update on this one - tracked it down and fixed it. Root cause: RFC 9458 §4.1 encapsulates requests with context.Seal("", request)the AEAD's additional authenticated data is empty, the header only feeds into info and the wire envelope. Our server was incorrectly using the header as the AEAD's AAD too, causing every real device request to fail authentication while our own (identically wrong) test script kept "succeeding" against it in lockstep, masking the bug for weeks. Fixed and deployed — the filter now shows "Running" on a real device for the first time. Thanks for your help narrowing down the Linux/OpenSSL HPKE issue earlier, that was a necessary step to get here. Closing this thread & and thanks again for the help
Replies
Boosts
Views
Activity
1d
Reply to NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
Hi Quinn @DTS Engineer, Just a gentle follow-up It's been somes days since my last message and I haven't found a solution yet on my end either, so wanted to check in. To recap where we're stuck: the manual HPKE reimplementation fixed the platform-specific Linux/OpenSSL CIPHER_R_BAD_DECRYPT issue you helped us trace (confirmed via self-constructed test requests succeeding consistently on both macOS and Linux now). But real requests coming from NEURLFilterManager on a physical iPhone still fail decapsulation with an AEAD authentication failure (HPKE open failed), while our own hand-built RFC 9458 requests against the same server succeed every time. So there's some remaining difference between how the real client constructs its OHTTP request and what we're decrypting on the server side that I haven't been able to identify from the spec alone. I was considering setting up a MITM proxy (mitmproxy) with a trusted root certificate installed on the iPhone, to capture the actual raw OHTTP POST body the device sends to our gateway and compare it byte-for-byte against what our server expects. Before I sink a weekend into that: Does that sound like a reasonable diagnostic approach to you, given NEURLFilterManager/the underlying network extension agent is a system-level component - is it likely to even respect a standard proxy/trust-store configuration, or does it bypass that layer entirely? Is there anything non-standard about how Apple's real OHTTP client builds the request that wouldn't be obvious from RFC 9458/9180 alone - e.g. a different info/aad construction, an intermediate relay reshaping the request, or key rotation/caching behavior on the client side that could cause it to encrypt against a stale key config? Or do you think I'm chasing the wrong thing entirely here, and the real issue is somewhere else (e.g. in how the key config or bloom prefilter is being fetched/cached on-device)? Thanks again for your help on this.
Replies
Boosts
Views
Activity
3d
Reply to NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
Hi @DTS Engineer Quinn made real progress based on your BAD_DECRYPT lead, with a new, more specific finding. I bypassed swift-crypto's HPKE.Recipient/HPKE.Sender entirely and implemented RFC 9180 base-mode HPKE manually using the lower-level primitives (Curve25519 key agreement, HKDF, AES-GCM) instead. Confirmed this resolves the platform-specific bug: a standalone HPKE test request I construct now decrypts successfully both locally on macOS and on the actual Fly.io/Linux deployment - identical result on both platforms now, where before it only worked on macOS. However, real requests from the iOS device still fail - now with a cleaner, more specific error: a genuine AEAD authentication failure (HPKE open failed), not the generic library crash from before. So my implementation correctly handles a standard RFC 9180 request, but something about the actual request the device sends doesn't match what I'm computing. Is there anything non-standard about how NEURLFilterManager/the PIR client constructs or routes these OHTTP requests that might not be obvious from the RFC - e.g., does it go through an Apple-operated OHTTP relay that re-encapsulates in transit, or is there a PIR-specific wrinkle in how info/aad are built that differs from generic OHTTP? Trying to figure out what to compare my reimplementation against, since I don't have visibility into the real device's raw request bytes. Thanks again - your BAD_DECRYPT read got us this far.
Replies
Boosts
Views
Activity
1w
Reply to NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
@Pushpak-Ambadkar123 hello, yes, I've dug a lot further on this. The full client-side sequence (on-device, Console.app filtered by NEPIRChecker) looks like this before that error: <NEPIRChecker>: -[NEPIRChecker start:responseQueue:completionHandler:] - Register with PIR Server (...) completed registration with PIR for Group ... <NEPIRChecker>: -[NEPIRChecker start:responseQueue:completionHandler:]_block_invoke - PIR status returned error <Error Domain=com.apple.CipherML Code=1100 ...>But the real root cause, if you also run your own PIR server and have access to its logs: on my server side, this traces back to an HPKE decapsulation failure in the OHTTP gateway Crypto.CryptoKitError.underlyingCoreCryptoError(error: 503316581)thrown from HPKE.Recipient(...)/.open(ct, authenticating:) when decrypting the incoming OHTTP request. I confirmed it's reproducible independently of the real client using a standalone HPKE test script, and that the failure rate seems to fluctuate with server uptime (worse after the process has been running a while) - pointing toward a possible concurrency issue around shared key material. Are you running your own PIR server, or hitting this purely from the client side? If you have server logs too, it'd be great to compare notes; might help build an even stronger case for @DTS Engineer Quinn.
Replies
Boosts
Views
Activity
1w
Reply to NEURLFilter PIR status check fails with CipherML errors (Code 1100/1800)
Hi @DTS Engineer Following up with a much more precise finding after digging into server-side logs. The failure is happening in our PIR server's OHTTP gateway, specifically in HPKE request decapsulation: [OHTTP] decapsulateRequest failed: Crypto.CryptoKitError.underlyingCoreCryptoError(error: 503316581)This is thrown from HPKE.Recipient(privateKey:ciphersuite:info:encapsulatedKey:) / .open(ct, authenticating:) (DHKEM(X25519, HKDF-SHA256) / HKDF-SHA256 / AES-128-GCM, per RFC 9458). What I've confirmed: Not an entitlement/config issueThe NEURL Filter configuration is correctly onboarded, and the client reaches this point successfully (handshake, registration all succeed first). Reproducible independently of the iOS client I wrote a standalone Python script using a real HPKE library (pyhpke), fetched our server's published /.well-known/ohttp-gateway key, and built a byte-for-byte RFC 9458-compliant OHTTP request against it. It fails with the exact same CryptoKitError.underlyingCoreCryptoError(error: 503316581). So this isn't specific to anything the iOS client does. Failure rate seems to fluctuate over server uptime Right after restarting the server process, a handful of real device requests briefly succeeded decryption (progressing to a later, unrelated parsing error), then it reverted to failing on essentially every attempt a few minutes later. This pattern makes me suspect a concurrency/thread-safety issue around the shared Curve25519.KeyAgreement.PrivateKey being used to construct a new HPKE.Recipient on every incoming request, rather than a static configuration problem. Any idea what corecrypto error 503316581 typically indicates, or whether there's a known gotcha with concurrent HPKE.Recipient construction from a shared private key in swift-crypto? Happy to share the Python repro script and/or file a bug with logs attached if that would help narrow it down. Thanks again for sticking with this one.
Replies
Boosts
Views
Activity
1w
Reply to NEURL Filter configuration approved under wrong Developer Team — resubmission blocked by duplicate domain
Hi @DTS Engineer — quick update now that the account transfer is confirmed onboarded on the good ID (thank you!). Running into a new, separate issue now when actually enabling the filter on device. The extension launches fine, XPC handshake succeeds, and PIR registration completes successfully. But the subsequent NEPIRChecker status check fails every time (retried repeatedly over several minutes, same result each time): PIR status returned error <Error Domain=com.apple.CipherML Code=1100 "Unable to query status due to errors: Error details were logged and redacted." UserInfo={NSLocalizedDescription=Unable to query status due to errors: Error details were logged and redacted., NSUnderlyingError=0x677037cf0 {Error Domain=com.apple.CipherML Code=1800 "Error details were logged and redacted." UserInfo={NSLocalizedDescription=Error details were logged and redacted.}}}>Config being registered (confirmed from the logs): pirServerURL = https://pir.dropbet.app/ pirPrivacyPassIssuerURL = https://pir.dropbet.app/issueBoth endpoints are live and were already validated as part of the original NEURL Filter configuration approval. I've captured a sysdiagnose from the device right when this was happening, so I have that ready to attach to a bug report if useful — just let me know and I'll file one. Any idea what CipherML error 1100/1800 typically indicates? Thanks again for all the help on this.
Topic: Code Signing SubTopic: Entitlements Tags:
Replies
Boosts
Views
Activity
1w
Reply to NEURL Filter configuration approved under wrong Developer Team — resubmission blocked by duplicate domain
Hello Quinn, Today I recive the mail about my onboarding : Your configuration [NE URL Filter] 9f3cbff8-63de-4c69-bf68-c19cd1c5d842 has been successfully onboarded and is now active. what´s the next step ? did i have to do something els for the transfer (FB24607828); or i have just to wait ? best regards & thanks again, Romain DropBet
Topic: Code Signing SubTopic: Entitlements Tags:
Replies
Boosts
Views
Activity
4w
Reply to NEURL Filter configuration approved under wrong Developer Team — resubmission blocked by duplicate domain
Got it, thanks for clarifying — that makes sense. Is there anything needed from my side for the onboarding step, or is it now entirely on Apple's end? And do you have any rough sense of timeframe (days, weeks, months) I should plan around, even approximate? Just trying to figure out whether to keep waiting or look at alternatives in the meantime.
Topic: Code Signing SubTopic: Entitlements Tags:
Replies
Boosts
Views
Activity
Sep ’26
Reply to NEURL Filter configuration approved under wrong Developer Team — resubmission blocked by duplicate domain
Thanks for looking into it, @DTS Engineer Quinn! Just to clarify though — this isn't a new PIR onboarding in progress. The configuration (ID 9f3cbff8-63de-4c69-bf68-c19cd1c5d842) was already fully approved back on Aug 5, so there's no review pending on the PIR server itself. The actual issue is that it's attached to the wrong Apple Developer Team (ex personnel acc Romain Scotto : S5VDH23BBZ instead of the organisation acc SCOTTO : KRKJ76BC7W), and the portal blocks any attempt to fix that with "A configuration with the same PIR Server Domain already exists." So there's nothing to wait out — it's purely a matter of reassigning the existing approved config to the correct team. Does that change things on your end?
Topic: Code Signing SubTopic: Entitlements Tags:
Replies
Boosts
Views
Activity
Sep ’26