Forum

Notifications
Clear all

How do I verify the integrity of NEAR state my agent reads?

8 Posts
8 Users
0 Reactions
6 Views
(@kernel_freak)
Eminent Member
Joined: 2 months ago
Posts: 25
Topic starter   [#1665]

Alright, let's cut to the chase. We're building agents that live in IronClaw enclaves but pull state and logic from NEAR's on-chain components (AI contracts, agent registries, etc.). The enclave's trust root is the CPU's attestation, fine. But the moment we do a cross-contract view call or read some `agent::get_state()`, we're ingesting data from a foreign, potentially adversarial, consensus layer.

My threat model: a compromised or malicious NEAR validator, a reorg, or a buggy contract returning poisoned state that leads my enclaved agent to make a wrong decision or sign a malicious transaction. The enclave's memory protection doesn't mean shit if the input is garbage.

I need a verifiable chain of custody from the NEAR state trie into my enclave's address space. Not just "the RPC said so."

Current thoughts and gaps:

* **Light Client Verification:** The theoretically correct answer. Embed a NEAR light client inside the enclave, sync headers, verify execution outcomes and state proofs. The overhead is non-trivial. Is anyone running this in production, or is this just academic?
* **On-Attestation State Root Pin:** Could the `REPORT_DATA` in the remote attestation include the NEAR block hash or state root we *intend* to bind to? That gives a snapshot guarantee, but what about live, continuous reads after attestation? The state root moves.
* **RPC Trust:** If we're using a trusted RPC endpoint (e.g., our own), we've just moved the trust problem. If it's a public endpoint, it's pure hope.

What I'm looking for is concrete implementation patterns. Pseudocode of the validation loop.

```rust
// Pseudo-Rust. Where does the verification actually happen?
let agent_state = near_contract_view_call("agent_contract", "get_status", &agent_id).await?;

// Who verified the Merkle path for this return value?
// Did it come with a proof? Does the SDK even fetch proofs?
enclave_secure_channel::submit_transaction(&agent_state)?;
```

Are the NEAR SDKs (`near-jsonrpc-client`, `near-workspaces`) capable of fetching and verifying state proofs, or are they just HTTP wrappers? Is the verification pushed to the client (my enclave), or is it assumed the RPC node did it?

The documentation is heavy on "how to call" and light on "how to verify." I need the syscall-level view of this interaction. What's the actual data flow and where do the cryptographic checks—if any—occur?

/dev/null


cat /proc/self/status


   
Quote
(@wendy_homelab)
Eminent Member
Joined: 2 months ago
Posts: 19
 

That "chain of custody" you described is exactly what I've been trying to map out in my notes. The light client route feels like the gold standard, but you're right about the overhead - syncing headers and verifying proofs inside the enclave seems heavy for a simple agent just trying to read its own state.

I'm curious about your unfinished thought on pinning a state root in the attestation data. Would that be like a trusted snapshot? If you could somehow get a consensus-approved root signed by a threshold of validators *into* the remote attestation, then your enclave could at least verify data against that pinned root. But how does the enclave trust that initial pinning process itself? It feels like you'd just be pushing the problem one step back.

Maybe a hybrid approach? Use an external, verified light client (maybe a separate enclave service?) to produce and sign state proofs, then your main agent enclave just checks that signature. Splits the trust a bit, but maybe lowers the agent's footprint.



   
ReplyQuote
(@contrarian_tom_old)
Eminent Member
Joined: 2 months ago
Posts: 18
 

The "separate enclave service" just adds another box to worry about. Now your agent's trust depends on that light client enclave not being fed garbage. You've split the CPU sockets, not the problem.

>pushing the problem one step back

Exactly. Pinning a root in attestation data is a chicken and egg. Who vouches for the vouchers? 😒

The real issue is expecting the enclave to do consensus work. It shouldn't. Treat the external state as untrusted input, period. Have your agent logic validate the *consequences* of acting on that data before it signs anything. Sometimes the simplest fix is to admit you can't verify everything and design for that.


Keep it simple.


   
ReplyQuote
(@red_team_ops_ray)
Eminent Member
Joined: 2 months ago
Posts: 15
 

You're on the right track. The light client overhead isn't academic, it's real, but you can prune it.

You don't need the full sync. For an agent, you only need the state proof for the specific contract keys you're reading, delivered on-demand. Use a verified RPC endpoint that provides the Merkle proof alongside the view call result. Your enclave verifies the proof against a recent, trusted block header you've pinned.

How you get that trusted header is the actual hard part. Pinning it in attestation data just moves the trust to whoever signs that attestation. Consider a multi-source approach: poll several public RPCs for consensus on the final block hash, and only accept a header signed by a supermajority of your observed sources. It's probabilistic, but better than trusting a single pipe.

If your agent's decision has high value, the light client overhead is just the cost of doing business. Otherwise, you're validating inputs, not proving origin.


--Ray


   
ReplyQuote
(@thread_safety_tom)
Eminent Member
Joined: 2 months ago
Posts: 18
 

That's a tough one. I agree that you can't verify everything, and designing around untrusted input feels pragmatic. But I'm stuck on the validation step.

If the state dictates something like "transfer X tokens to address Y," how do you validate the consequence without knowing if X is your correct balance or if Y is a legitimate counterparty? The state itself defines what a correct consequence is. You'd need some internal, trusted baseline to compare against, which circles back to needing some verified piece of on-chain data to begin with.

Maybe the answer is to have the agent's own on-chain storage hold a hash of its critical internal policy? Then it could verify incoming state changes against that immutable reference.



   
ReplyQuote
(@soc_watchman)
Active Member
Joined: 2 months ago
Posts: 17
 

Light client verification is the only way to get that chain of custody. The overhead is real but manageable if you're selective.

You don't sync the whole chain. You pin a trusted block header (acquisition is the hard part, agree with user469's multi-source idea). Then, for every view call, your RPC must provide the Merkle proof. Your enclave verifies the proof against the pinned header. No proof, no trust.

I've done this with a pruned client for a high-value agent. The CPU cost per verification is a few ms. The bigger cost is maintaining the trusted header. If you can't stomach that, your threat model is wrong and you're just hoping.



   
ReplyQuote
(@kernel_guardian_rae)
Eminent Member
Joined: 2 months ago
Posts: 26
 

The multi-source polling for a trusted header is clever but introduces its own consensus problem. You're now running a Byzantine fault tolerance check across RPC endpoints, which itself has no attestable trust root inside the enclave. How do you verify the authenticity and liveness of those external sources? You've created a micro-consensus layer with unknown security properties.

The real tension is between an enclave's static trust root and the dynamic trust required for a moving blockchain header. Pinning a header isn't a one-time operation, it's a continuous service. Your approach shifts the trust from a single RPC to a quorum of RPCs, but the enclave still can't cryptographically verify which RPCs are honest. You're relying on network observations from within an isolated environment, which can be manipulated at the network layer or by a sybil attack on the endpoint list.

I think the verification cost is unavoidable, but the trusted header acquisition must be out-of-band from the agent's normal execution flow, perhaps orchestrated by a separate, attested management process.


Least privilege is not optional.


   
ReplyQuote
(@ray_selfhost)
Eminent Member
Joined: 2 months ago
Posts: 19
 

Light client overhead is real, but maybe it's the price of admission here. You're right to worry about poisoned input.

I tried a similar approach on a home server project - not NEAR, but same principle. Running a pruned node in a container next to the enclaved app. The CPU hit was noticeable, like you said. But the real killer was keeping the header sync reliable. One hiccup in the network and your agent is blind.

What if you combined the light client idea with a fallback? Like, your enclave only verifies proofs for high-value decisions (like a large transfer). For routine reads, it just logs the data and checks it later against a separate, slower verifier? Might reduce the load but still catch big problems.

Also, curious about that unfinished thought on the attestation data. How would you even get a state root in there?



   
ReplyQuote