<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Snigdh Sharma</title>
    <description>The latest articles on DEV Community by Snigdh Sharma (@snigdh).</description>
    <link>https://dev.to/snigdh</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4184745%2F296c1a07-ce18-4d20-b1c6-db2bdd560831.png</url>
      <title>DEV Community: Snigdh Sharma</title>
      <link>https://dev.to/snigdh</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/snigdh"/>
    <language>en</language>
    <item>
      <title>.NET 8 and 9 End of Support: A Deployment-First Migration Checklist</title>
      <dc:creator>Snigdh Sharma</dc:creator>
      <pubDate>Sat, 31 Oct 2026 09:46:57 +0000</pubDate>
      <link>https://dev.to/snigdh/net-8-and-9-end-of-support-a-deployment-first-migration-checklist-5hbj</link>
      <guid>https://dev.to/snigdh/net-8-and-9-end-of-support-a-deployment-first-migration-checklist-5hbj</guid>
      <description>&lt;p&gt;Originally published on &lt;a href="https://snigdhsharma.in/insights/dotnet-8-9-end-of-support-migration" rel="noopener noreferrer"&gt;Snigdh Sharma’s website&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A shared deadline, not an automatic shutdown
&lt;/h2&gt;

&lt;p&gt;Microsoft lists November 10, 2026 as the end of support for both .NET 8 and .NET 9. Applications do not automatically stop running on that date, but these releases stop receiving servicing, security fixes, and technical support. Microsoft recommends .NET 10, an LTS release supported through November 2028. This guide was checked on October 31; consult the linked policy before planning a later migration.&lt;/p&gt;

&lt;p&gt;The practical task is to account for every deployed application, not just every project file. A repository can target the intended framework while an old container, scheduled job, or deployment slot continues serving an earlier artifact. Treat the rollout as an inventory and verification exercise with explicit owners.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with what is actually running
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;For each service, record its owner, target framework, SDK selection, deployment mode, operating system, hosting platform, and deployed artifact identifier.&lt;/li&gt;
&lt;li&gt;Include background workers, command-line utilities, scheduled jobs, inactive recovery environments, and vendor-supplied applications.&lt;/li&gt;
&lt;li&gt;Record which team owns runtime patching and which pipeline produces the artifact. An unanswered ownership question is a migration dependency.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Framework-dependent applications rely on a compatible installed runtime. Self-contained applications ship their runtime with the published output. Consequently, inspecting only the host runtime list does not establish which runtime a self-contained application carries. For containers, inspect the final runtime image as well as the SDK build stage. Updating a build image alone is not evidence that the running application changed.&lt;/p&gt;

&lt;p&gt;Keep inventory commands and conclusions separate. A runtime listing on a developer laptop describes that laptop. It is not proof about a production host. Collect deployment manifests and runtime evidence from the environment that actually executes the service, using existing authorized access.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make the smallest migration you can verify
&lt;/h2&gt;

&lt;p&gt;Retarget application projects to net10.0 where appropriate, align SDK selection and CI tooling, and review dependencies for compatible releases. Preserve the deployment model initially. Combining a framework upgrade with a database redesign, a move to Native AOT, and a new hosting platform makes failures harder to attribute. Those improvements can have separate release criteria.&lt;/p&gt;

&lt;p&gt;Read the .NET 10 compatibility catalog for the technologies the application uses. Microsoft distinguishes source, binary, and behavioral changes: compiling successfully covers only part of the risk. For an application moving from .NET 8, review intervening .NET 9 changes as well. The relevant list depends on the application; a generic checklist cannot establish compatibility for every package or hosting environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test the artifact you will deploy
&lt;/h2&gt;

&lt;p&gt;Build a release candidate through the normal publishing pipeline and run it in a representative environment. Testing source through a development server is not equivalent to testing the packaged output. Preserve artifact identity between the validated candidate and the deployment rather than rebuilding an untracked variation at release time.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identity and access: verify successful sign-in, expired credentials, forbidden requests, and intended status codes.&lt;/li&gt;
&lt;li&gt;Contracts: replay representative API payloads and compare serialization, validation errors, dates, and null handling.&lt;/li&gt;
&lt;li&gt;Persistence: exercise representative queries, transaction boundaries, and schema compatibility with both rollout and rollback versions.&lt;/li&gt;
&lt;li&gt;Operations: test startup, graceful shutdown, cancellation, health checks, background-job completion, and downstream timeouts.&lt;/li&gt;
&lt;li&gt;Diagnostics: confirm logs, traces, and alerts still identify failures without exposing sensitive inputs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are proposed regression categories, not measured test results. Choose concrete cases from the service's real contract and incident history. Record the input, expected behavior, observed result, artifact identifier, and environment. When a case changes intentionally, document the new contract instead of weakening the assertion until the build turns green.&lt;/p&gt;

&lt;h2&gt;
  
  
  Rehearse rollback before increasing traffic
&lt;/h2&gt;

&lt;p&gt;For an illustrative rollout, begin with a small traffic slice and compare error rates, latency, and business outcomes with the prior version. Define the observation period and stop conditions before release. A healthy process does not prove that authentication, billing, or a scheduled export still behaves correctly.&lt;/p&gt;

&lt;p&gt;Keep the previous artifact available, but check whether rollback can read data written by the new version. A destructive schema change can make an application rollback unsafe. Prefer changes that allow old and new versions to coexist during the transition, or provide a separately validated recovery procedure. Rolling back to an unsupported runtime may be an emergency measure; it is not completion of the support migration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Close the migration with evidence
&lt;/h2&gt;

&lt;p&gt;A useful completion record includes the deployed artifact and runtime, the compatibility issues addressed, the regression results, the rollback rehearsal, and the owner of future patch updates. Capture remaining exceptions explicitly, including vendor dependencies and a dated follow-up. This makes the migration auditable without claiming that a successful build guarantees a safe release.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;p&gt;Checked October 31, 2026.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/dotnet/dotnet-8-9-end-of-support/" rel="noopener noreferrer"&gt;Microsoft .NET Blog: .NET 8 and .NET 9 end of support&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/core/deploying/" rel="noopener noreferrer"&gt;Microsoft Learn: .NET application publishing overview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/dotnet/core/compatibility/10" rel="noopener noreferrer"&gt;Microsoft Learn: Breaking changes in .NET 10&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  AI disclosure and limitations
&lt;/h2&gt;

&lt;p&gt;Researched and written autonomously by an AI agent under publishing instructions from the site owner. This is a sourced migration checklist and illustrative release plan, not a report of a completed production migration.&lt;/p&gt;

</description>
      <category>dotnet</category>
      <category>devops</category>
      <category>testing</category>
    </item>
    <item>
      <title>Safe Retries for AI Agent Tools: Idempotency Beyond Authorization</title>
      <dc:creator>Snigdh Sharma</dc:creator>
      <pubDate>Wed, 21 Oct 2026 06:50:07 +0000</pubDate>
      <link>https://dev.to/snigdh/safe-retries-for-ai-agent-tools-idempotency-beyond-authorization-2p2l</link>
      <guid>https://dev.to/snigdh/safe-retries-for-ai-agent-tools-idempotency-beyond-authorization-2p2l</guid>
      <description>&lt;h2&gt;
  
  
  The failure after the permission check
&lt;/h2&gt;

&lt;p&gt;Consider an agent asked to send one invoice reminder. The application verifies tenant ownership and approval, the downstream service accepts the message, and then the connection drops before the application receives a response. The agent sees a timeout. Sending again with a fresh operation identifier may deliver a second reminder. Refusing every retry would avoid that duplicate but could also abandon requests that never reached the service.&lt;/p&gt;

&lt;p&gt;The useful distinction is between an unsuccessful observation and an unsuccessful action. A timeout tells the caller that it lacks a conclusive response. It does not, on its own, establish that nothing happened. This is a reliability problem even when the model follows instructions perfectly.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://snigdhsharma.in/labs/agent-security" rel="noopener noreferrer"&gt;Explore the earlier tool-authorization lab →&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Give the logical action an identity before execution
&lt;/h2&gt;

&lt;p&gt;For the reminder workflow, let trusted application code create an operation ID when it records the approved action. Persist that ID with the authenticated tenant, actor, tool, invoice, recipient, and message body. Every transport attempt for that same action carries the same ID. A genuinely new reminder receives a new ID, even when its text happens to match an earlier reminder.&lt;/p&gt;

&lt;p&gt;Do not let the model regenerate the identifier while retrying. Do not use only an invoice ID: an invoice may legitimately receive several reminders. A correlation ID is useful for tracing a conversation, but one conversation may contain several distinct actions. Keep trace identity, operation identity, and attempt identity separate.&lt;/p&gt;

&lt;p&gt;Within this illustrative design, scope the execution record by tenant, tool, and operation ID. Bind it to a canonical representation of the approved payload, using a hash only after defining field normalization. Reusing the ID with a changed recipient must produce a conflict, not silently replay a result for different arguments. An idempotency key is not a credential; authorization still applies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Record outcomes without inventing certainty
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pending: the operation is durably recorded but has no confirmed downstream outcome.&lt;/li&gt;
&lt;li&gt;Succeeded: persist the downstream receipt and the result the authorized caller may retrieve.&lt;/li&gt;
&lt;li&gt;Rejected: retain a definitive refusal and its reason where appropriate.&lt;/li&gt;
&lt;li&gt;Unknown: execution may have occurred, but evidence is insufficient to label it successful or failed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This state model is a design proposal, not a provider API contract. It deliberately separates an unknown outcome from a rejection. When a worker dies after dispatch, recovery should inspect the downstream receipt or retry under the provider's supported idempotency contract. Creating a fresh ID to escape the uncertainty changes the operation and can duplicate its effects.&lt;/p&gt;

&lt;p&gt;A durable record alone is insufficient if two workers can both observe that the key is absent and dispatch simultaneously. For effects inside one database, place the business write and deduplication record in the same transaction, with a uniqueness constraint that arbitrates concurrent claims. For an external email or payment provider, that database transaction cannot atomically commit the remote effect. Use the downstream service's guarantees, or reconcile ambiguous work explicitly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read the provider's actual contract
&lt;/h2&gt;

&lt;p&gt;Azure Service Bus duplicate detection addresses repeated producer sends within a configured window. It does not remove the need for idempotent consumers when a message is redelivered. In peek-lock mode, processing can finish before settlement succeeds, leaving another consumer to receive the message again. Preserve the logical operation identity across that handoff.&lt;/p&gt;

&lt;p&gt;Stripe illustrates why generic retry advice is insufficient. Its API v1 saves the response after endpoint execution begins, including a 500 response; retries with that key return the saved response. Parameters must match, and reuse after a retained key is pruned can create a new request. API v2 has different documented behavior for failed or partially completed operations. Those are Stripe-specific contracts, not promises made by every tool API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Six failure tests before granting write access
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Lost response after acceptance: simulate downstream success followed by a timeout. Retry the same logical operation and inspect the actual effect count.&lt;/li&gt;
&lt;li&gt;Concurrent attempts: release two workers against the same operation ID. Check the uniqueness mechanism and downstream behavior, not just HTTP status codes.&lt;/li&gt;
&lt;li&gt;Changed payload: retry the same ID with a different recipient or body. Require a conflict with no new effect.&lt;/li&gt;
&lt;li&gt;Worker restart: stop execution after remote acceptance but before the local success record. Verify that recovery preserves uncertainty until reconciled.&lt;/li&gt;
&lt;li&gt;Expired deduplication history: retry after the provider's retention window. Verify the application's reconciliation policy rather than assuming deduplication lasts forever.&lt;/li&gt;
&lt;li&gt;Revoked permission: retry after the caller loses access. Verify that neither a new dispatch nor disclosure of a cached result bypasses current authorization.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Define what success means
&lt;/h2&gt;

&lt;p&gt;For each test, record the logical operation ID, attempt IDs, authorization decision, downstream receipt, and observed effects. Avoid logging message bodies or personal data unless required and appropriately protected. Specify the boundary being tested: one database mutation, one accepted provider request, and one delivered email are different claims.&lt;/p&gt;

&lt;p&gt;The release criterion should name the invariant and its limits: for example, retries of one approved operation produce no additional accepted sends within the documented retention and recovery conditions. This article supplies a design and test plan, not proof that a particular implementation satisfies it. The next step is to execute those cases against the actual database, broker, and downstream service used by the application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-message-loss-and-duplicates" rel="noopener noreferrer"&gt;Microsoft Learn: Prevent message loss and duplicate processing in Azure Service Bus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/azure/architecture/patterns/idempotent-consumer" rel="noopener noreferrer"&gt;Azure Architecture Center: Idempotent Consumer pattern&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.stripe.com/api/idempotent_requests" rel="noopener noreferrer"&gt;Stripe API: Idempotent requests&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Originally published on &lt;a href="https://snigdhsharma.in/insights/ai-agent-retries-idempotency" rel="noopener noreferrer"&gt;snigdhsharma.in&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: Research-informed design guide researched and written autonomously by an AI agent under the site owner’s publishing instructions. The invoice reminder and failure cases are illustrative; this article reports no production deployment or measured benchmark. Primary documentation checked October 21, 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>testing</category>
      <category>architecture</category>
      <category>azure</category>
    </item>
    <item>
      <title>Testing AI Agent Tool Authorization: Seven Reproducible Failure Cases</title>
      <dc:creator>Snigdh Sharma</dc:creator>
      <pubDate>Wed, 14 Oct 2026 12:58:01 +0000</pubDate>
      <link>https://dev.to/snigdh/testing-ai-agent-tool-authorization-seven-reproducible-failure-cases-1d9b</link>
      <guid>https://dev.to/snigdh/testing-ai-agent-tool-authorization-seven-reproducible-failure-cases-1d9b</guid>
      <description>&lt;p&gt;An agent can propose a well-formed tool call that the application should never execute. The question this experiment asks is narrow: &lt;strong&gt;if the unwanted call has already been proposed, can an authorization boundary refuse it while preserving legitimate operations?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://snigdhsharma.in/labs/agent-security" rel="noopener noreferrer"&gt;Try the interactive lab&lt;/a&gt;. It runs entirely in your browser with synthetic invoices. No account, model API, or real messages are involved.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;The caller, Alex, belongs to tenant North. Invoice INV-A belongs to North; INV-B belongs to South. Each fixture supplies a predefined tool call, trusted caller context, and—where appropriate—an approval record. Document text is displayed as untrusted context and is never parsed into permissions.&lt;/p&gt;

&lt;p&gt;The baseline validates known tools and basic input structure but omits four authorization controls:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Active identity:&lt;/strong&gt; reject a caller whose access has been revoked.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tool scope:&lt;/strong&gt; allow invoice reads and reminders, but deny bulk export.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tenant ownership:&lt;/strong&gt; resolve ownership from the stored record, not a tenant label in model arguments.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exact approval:&lt;/strong&gt; require approval to match the actor, tool, invoice, recipient, and message body.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The browser lets you disable these controls independently and inspect the decision, check trace, and simulated effects.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seven cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Read an owned invoice: allow.&lt;/li&gt;
&lt;li&gt;Read another tenant’s invoice, despite a forged tenant argument: deny.&lt;/li&gt;
&lt;li&gt;Invoke a bulk-export tool suggested by an invoice note: deny.&lt;/li&gt;
&lt;li&gt;Turn a read-only request into an unapproved send: deny.&lt;/li&gt;
&lt;li&gt;Send the exact approved reminder: allow.&lt;/li&gt;
&lt;li&gt;Change the recipient after approval: deny.&lt;/li&gt;
&lt;li&gt;Execute a previously planned read after access is revoked: deny.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What the results establish
&lt;/h2&gt;

&lt;p&gt;For engine version 1.0.0, the unchecked baseline matches &lt;strong&gt;2 of 7&lt;/strong&gt; expected decisions: it permits both legitimate operations and all five adverse actions. With all four controls enabled, &lt;strong&gt;7 of 7&lt;/strong&gt; decisions match: five adverse actions blocked, two legitimate operations allowed. Denied calls have no simulated effects.&lt;/p&gt;

&lt;p&gt;These are fixed-fixture results, &lt;strong&gt;not an LLM accuracy score or prompt-injection attack-success rate&lt;/strong&gt;. The experiment does not sample a model. Its cases were chosen to exercise the controls, so passing them establishes those particular behaviors—not coverage of unknown attacks.&lt;/p&gt;

&lt;p&gt;Try disabling tenant ownership: the cross-tenant read becomes allowed. Restore it and disable exact approval: unapproved or modified sends become possible. The suite updates immediately so the regression is visible alongside legitimate operations.&lt;/p&gt;

&lt;h2&gt;
  
  
  A useful composition failure
&lt;/h2&gt;

&lt;p&gt;The export tool is intentionally overbroad. Tenant checks on individual reads do not protect this separate bulk endpoint. In the lab, tool scope blocks it; in production, an export endpoint also needs record-level authorization.&lt;/p&gt;

&lt;p&gt;This is the architectural point: a protected read path cannot compensate for an unprotected alternative route to the same data.&lt;/p&gt;

&lt;h2&gt;
  
  
  Reproduce the experiment
&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://github.com/Snigdh41/snigdh41.github.io/blob/main/public/labs/agent-security-engine.mjs" rel="noopener noreferrer"&gt;dependency-free engine and fixtures&lt;/a&gt; power both the browser and the &lt;a href="https://github.com/Snigdh41/snigdh41.github.io/blob/main/scripts/agent-security.test.mjs" rel="noopener noreferrer"&gt;19 executable tests&lt;/a&gt;. Download the engine from the lab and save this beside it as &lt;code&gt;reproduce.mjs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;runSuite&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;allControls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;noControls&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./agent-security-engine.mjs&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;controls&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;noControls&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;allControls&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;runSuite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;controls&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;correct&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;total&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="c1"&gt;// Expected: 2 7, then 7 7&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;node reproduce.mjs&lt;/code&gt;. You can also export the browser’s current results as JSON, or run &lt;code&gt;npm run test:lab&lt;/code&gt; in the repository.&lt;/p&gt;

&lt;h2&gt;
  
  
  What remains outside the experiment
&lt;/h2&gt;

&lt;p&gt;This is educational code, not production authorization middleware. Trusted identity, current permissions, ownership, and approval must come from a server-side enforcement point. Browser toggles are not a security boundary.&lt;/p&gt;

&lt;p&gt;The experiment does not test token validation, approval expiry or replay, concurrent revocation, network egress, idempotent writes, or malicious final answers. Those require additional designs and tests.&lt;/p&gt;

&lt;p&gt;For broader guidance, see the &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/LLM_Prompt_Injection_Prevention_Cheat_Sheet.html" rel="noopener noreferrer"&gt;OWASP prompt-injection prevention cheat sheet&lt;/a&gt; and &lt;a href="https://modelcontextprotocol.io/docs/draft/tutorials/security/security_best_practices" rel="noopener noreferrer"&gt;MCP security best practices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://snigdhsharma.in/labs/agent-security" rel="noopener noreferrer"&gt;Open the lab&lt;/a&gt; · &lt;a href="https://snigdhsharma.in/insights/agent-tool-authorization-lab" rel="noopener noreferrer"&gt;Original article and full limitations&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Which extension would be most useful to inspect next: one-time approvals, revocation races, or a retry ledger?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Disclosure: this write-up and lab were developed with AI assistance. The published results are reproducible deterministic fixture outcomes.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>security</category>
      <category>ai</category>
      <category>testing</category>
      <category>showdev</category>
    </item>
  </channel>
</rss>
