Split out from the #4996 (own-profile editing) review (graycyrus).
Context
handle_tinyplace_users_update_profile (src/openhuman/tinyplace/manifest.rs:400) passes a client-supplied cryptoId straight to client.users.update_profile(&crypto_id, update) without checking it against the caller's signer identity. #4996 is the first PR to make this write path reachable from a real UI.
Why this is not exploitable from the OpenHuman app today
The authorization is cryptographic on the SDK/backend seam, not trust-based at the RPC layer:
- The SDK signs the canonical
user.profile payload, which includes "cryptoId": crypto_id (vendor/tinyplace/sdk/rust/src/api/users.rs:124), with the caller's wallet signer (:37-42).
- The HTTP layer presents the signer's public key alongside the signature (
vendor/tinyplace/sdk/rust/src/http.rs:412-428).
cryptoId is the wallet's Solana address, so signing with your own key for another cryptoId presents a public key that does not match the target — the backend can reject it.
- The core always uses the local wallet as signer, and
/rpc is token-gated to the app; the ProfilesSection UI only ever passes the user's own cryptoId. So no cross-user update path is reachable from the client.
Ask (tracking)
Confirm the tiny.place backend (separate repo) verifies that the presented public key owns the cryptoId being updated (i.e. rejects a valid signature whose key ≠ the target cryptoId owner) for PUT /users/{cryptoId}/profile. This is defense-in-depth verification of the documented signed-request contract ("presents the signing key so the backend can authorize the update"), not a disclosed client-reachable exploit.
No code change required in openhuman for #4996; filing so the backend-side guarantee is confirmed rather than assumed.
Split out from the #4996 (own-profile editing) review (graycyrus).
Context
handle_tinyplace_users_update_profile(src/openhuman/tinyplace/manifest.rs:400) passes a client-suppliedcryptoIdstraight toclient.users.update_profile(&crypto_id, update)without checking it against the caller's signer identity. #4996 is the first PR to make this write path reachable from a real UI.Why this is not exploitable from the OpenHuman app today
The authorization is cryptographic on the SDK/backend seam, not trust-based at the RPC layer:
user.profilepayload, which includes"cryptoId": crypto_id(vendor/tinyplace/sdk/rust/src/api/users.rs:124), with the caller's wallet signer (:37-42).vendor/tinyplace/sdk/rust/src/http.rs:412-428).cryptoIdis the wallet's Solana address, so signing with your own key for another cryptoId presents a public key that does not match the target — the backend can reject it./rpcis token-gated to the app; the ProfilesSection UI only ever passes the user's owncryptoId. So no cross-user update path is reachable from the client.Ask (tracking)
Confirm the tiny.place backend (separate repo) verifies that the presented public key owns the
cryptoIdbeing updated (i.e. rejects a valid signature whose key ≠ the target cryptoId owner) forPUT /users/{cryptoId}/profile. This is defense-in-depth verification of the documented signed-request contract ("presents the signing key so the backend can authorize the update"), not a disclosed client-reachable exploit.No code change required in openhuman for #4996; filing so the backend-side guarantee is confirmed rather than assumed.