Architecting an Agent Around a Data Moat
The company below, Meridian, is a composite. It isn't a real business, and nothing here describes an actual client engagement.
Meridian is a B2B marketplace that connects buyers and suppliers across a fragmented industrial category. Its product is fine. Its moat isn't the product. It's eight years of transaction history: what buyers actually paid, which supplier-buyer matches held up over time, which pricing patterns predict a deal falling through, which suppliers quietly underbid to win share before raising prices later. A competitor could clone the marketplace UI in a quarter. Nobody can reproduce the eight years of transaction history that Meridian owns.
Meridian's pricing, risk, and business development teams currently get insight out of that dataset through analysts. Someone files a request, an analyst writes SQL, a few days later there's an answer. The obvious fix is an agent: let people ask questions in plain language and get answers against the warehouse directly. That's also where the interesting engineering problem starts.
The product requirement
The product requirement is straightforward: unlock the dataset for the people who need it, without the analyst bottleneck. The obvious security answer is also straightforward: restrict what the agent can see.
The problem is that restricting the agent's data access far enough to feel safe mostly defeats the product. The pricing team's actual questions are open-ended: which supplier categories are showing margin compression, is a particular buyer's payment behavior drifting toward risk, which markets look under-served relative to historical demand. An agent that can only answer three pre-approved question templates isn't the product Meridian is trying to build. It's a slightly fancier dashboard.
So the agent needs broad analytical reach across a dataset that is, by construction, the company's most sensitive asset.
Four failure modes
It's worth being explicit about who the design has to hold up against, because "security" as a single word hides at least four different threats with different capabilities.
1. Someone with legitimate access to the agent, no malicious intent, who asks a sequence of individually reasonable questions that happen to reconstruct something they were never supposed to see directly. This is the most common case and the easiest to dismiss as not a real threat.
2. Same access, different intent: someone deliberately trying to extract as much proprietary signal as possible before they leave, or on someone else's behalf.
3. An attacker who's gained control of an authenticated session or the agent's own execution context, not through any weakness in the data layer, but through a compromised laptop, a stolen token, a supply-chain issue in a tool the agent calls.
4. Nobody malicious at all, just an aggregate question that happens to have a small enough denominator to reveal something specific. A pricing analyst asking about a niche supplier category with three players in it doesn't need bad intent to expose a competitively sensitive number.
Initial architecture
The first design is in a lot ways, intuitive. Four principles, each mapped to a role rather than a specific vendor:
Data minimization: The agent never touches raw transaction tables. Those sit in the highest sensitivity tier of the warehouse (in this stack, S3 and Delta Lake, governed through Unity Catalog) and nothing agent-facing reads from them directly. The agent queries a layer of pre-built, pre-aggregated views instead, each with a minimum row-count threshold baked in, so no single query can return a result granular enough to identify one counterparty.
Explicit orchestration: The agent runtime is a Python service, not a black-box managed agent framework, specifically because every tool call, query, and response needs to be inspectable and logged. This is the same observability principle from the governance-review work: a reviewer approving this system needs to be able to reconstruct what happened, not just see the final answer.
A narrow action surface: The agent gets read tools against the governed views and nothing else. No write access, no email, no API calls out, no way to communicate beyond returning a chat response to the person who asked.
Identity-scoped execution: The agent doesn't carry one fixed set of permissions to the semantic layer. Every query executes under the requesting user's own entitlements, so someone in BD and someone in Risk asking the same question against the same governed views get answers scoped to what each of them is actually allowed to see, not whatever the agent's own service account happens to have access to. Identity has to constrain the query before it runs, not just get attached to the log entry afterward.
Audit logging: Every query, tool call, and returned result gets logged, tied to the requesting user and session.
This is a first attempt architecture, and against three of the four adversaries above it does okay. It stops write-based sabotage outright. It stops a compromised session from directly reading raw records. It gives a reviewer something to audit.
But, it doesn't stop a curious employee from asking the right sequence of questions.
Red-teaming it
Here's the failure mode that a row-count threshold alone can't catch. Say the minimum-row rule requires at least ten counterparties in any aggregate.
Query one: "What's the average price across the twelve suppliers in category X?" Answer: $84,000. That satisfies the threshold, twelve is well above ten.
Query two: "Same question, excluding supplier A." Eleven suppliers remain, still above the threshold. Answer: $86,000.
Both queries are individually authorized. Both clear the row-count rule. But together:
(12 × $84,000) − (11 × $86,000) = $62,000
That's supplier A's exact price, reconstructed from two answers nobody flagged as a problem, because nobody was checking the two queries against each other. WHERE count(*) >= 10 is a real control against any single query. It's not a control against a sequence of them, and a curious employee doesn't need any special skill to find this pattern, just persistence and a spreadsheet.
This is the actual engineering problem. The threat isn't unauthorized access, it's authorized access, used repeatedly, in a pattern the system was never taught to watch for.
The answer is the egress
There's a second problem sitting underneath the first one. Even without a differencing attack, once the agent returns a legitimate aggregate number to someone authorized to see it, that number is now sitting in a chat window. A human export gate on bulk downloads doesn't help here, because nobody needed to trigger a bulk export. The information already left the system the moment it appeared on screen. For a data agent specifically, the response channel isn't adjacent to the egress surface. It is the egress surface.
That rules out the tempting fix of "add stronger controls on exports." Exports were never the leak. The chat response was, and no export gate touches a chat response.
The only design that actually addresses this doesn't try to control what a person does with an answer they were legitimately given. It tries to make sure the only answers ever produced are the aggregate, non-reconstructable kind, and catches the reconstruction attempt before an answer is generated.
Refined architecture
The fix is a disclosure policy gate sitting between the agent and the governed views, evaluating every query against a user's own recent history before the query runs. Calling it a monitor undersells what it has to do: a monitor watches and reports. This has to block the second query in a differencing pair before an answer that would complete the reconstruction ever gets generated.
Cumulative disclosure tracking. The system tracks, per user and per rolling window. Two queries against the same category that differ by excluding a single entity are exactly the shape of a differencing attack, whether or not the person asking intends it that way. A first version could reasonably start narrow: track near-identical queries that differ by one excluded entity, and flag or block the second one before it returns an answer. That won't solve reconstruction generally, since real attacks can chain multiple partial overlaps, different predicates, or outside information across sessions, but it closes the simplest version of the attack above and gives something concrete to red-team.
None of this is a new problem. Statistical disclosure control and privacy-preserving query systems have dealt with versions of cumulative leakage for decades, well before anyone was building agents. What's new here is the interface. A natural-language agent makes generating and iterating through exactly this kind of query sequence dramatically cheaper than writing SQL by hand ever was, which is exactly why a control that used to be optional is closer to mandatory now.
Query budgets tied to specificity: A high volume of broad questions is normal usage. A moderate volume of narrow, overlapping questions on the same slice of data is a different pattern entirely, and it should be rate-limited and reviewed even if no single query looks abnormal.
Anomaly detection on query sequences: This runs alongside the audit log rather than replacing it: the log tells a reviewer what happened after the fact, the sequence monitor is what catches a reconstruction attempt while it's still in progress.
Tighter thresholds for high-sensitivity categories: Not every part of the dataset carries the same risk if reconstructed. Categories with few counterparties, or with pricing volatile enough that a single number reveals a lot about strategy, get a higher minimum-row threshold and a lower tolerance for near-miss overlapping queries than the rest of the warehouse.
None of this touches the export gate from the first architecture, which still has a real job: legitimate scheduled reports and bulk feeds to downstream systems, where a human should be reviewing what's actually leaving in bulk. That control was never wrong. It just isn't the control that stops a differencing attack, because a differencing attack never goes anywhere near it.
Testing the second architecture against all four adversaries
The curious employee is now the primary case the design targets, and cumulative disclosure tracking catches the pattern regardless of intent, because it doesn't depend on inferring intent. The departing or malicious insider faces the same controls, plus the query-budget layer, which makes a deliberate high-volume extraction attempt slower and more visible, not just theoretically detectable, though a determined attacker with enough patience and enough separate sessions is still a harder case than the architecture above fully closes. The compromised session inherits every control above it, since it's still going through the same identity-scoped queries and the same disclosure gate, which limits the blast radius to whatever that one user's entitlements actually cover rather than whatever the agent's own service account could reach. The narrow action surface from the first architecture still holds too: even a fully compromised session can't write, export in bulk, or communicate externally without tripping the human-reviewed gate. The sensitivity-tiered thresholds reduce the risk from an accidental over-broad query, since the categories most likely to produce an accidentally revealing answer are exactly the ones with the tightest row-count and overlap rules, though a threshold reduces the odds of an accidental leak rather than eliminating it.
What it doesn't solve, and what no architecture at this layer can solve, is a user who's legitimately authorized to see a genuinely safe answer choosing to misuse that information afterward. That's not a data architecture problem anymore.
Utility, security, and the tradeoff between them
None of this is worth building unless it meaningfully beats the status quo. Before shipping, the agent needs to prove three things: it answers real business questions better and faster than the analyst-mediated process, its disclosure controls prevent reconstruction attacks without getting in the way of legitimate work, and its latency and cost justify replacing the existing workflow.
The problem inherently becomes more focused on the tradeoffs - every constraint added to stop reconstruction, tighter thresholds, more aggressive overlap detection, lower query budgets, also reduces how precisely the agent can answer a legitimate question. Push the thresholds too high and you're back to the fancier-dashboard problem the whole project was trying to avoid. Push them too low and the differencing attack comes back. The engineering question isn't "can this be made perfectly secure." It's how much analytical value the system can preserve for a given, explicitly chosen level of acceptable extraction risk, and that number has to be a decision someone signs off on, not a default that falls out of whatever thresholds seemed reasonable at build time.
Limitations
This is simply a proposed architecture. I haven't run the red-team exercise described above, so I don't know where the real breaking point sits between utility and security for a dataset and query pattern like Meridian's. The differencing attack described here is the simplest version of the pattern; more sophisticated variants (using multiple partial overlaps, or combining public information with agent answers) likely exist and would need their own testing. And the four-adversary framing above is simply a reasonable starting list. A real deployment would need its own threat-modeling pass specific to what Meridian's data actually looks like.
What I'd build and test first
Before anything else: a minimal version of the cumulative disclosure tracker, tested against a deliberately constructed differencing attack like the one above, to see how quickly it catches the pattern and how many false positives it generates against normal analyst-style query behavior. That single test would tell me more about whether this architecture is viable than any amount of further design work would.

Architecture diagram: the layered design described above, with identity and the agent runtime issuing queries down through a disclosure policy gate into the governed views and raw data, and allowed answers returning back up through that same gate to the chat response, is below. The separate bulk-export path branches off the governed views layer directly.