At endjin, we maintain Corvus.JsonSchema, and in the previous post we generated a strongly-typed HTTP client from an OpenAPI spec.
Now let's flip to the server side.
If you've built an ASP.NET Core API by hand, you know how much code goes into not doing business logic. You parse a query parameter, check it's present, check it's the right type, check it's within range, parse the body, validate required fields, and return a 400 with a useful message if anything is off. You can easily spend more lines on input validation than on the actual operation.
And there's a worse problem: drift. The spec says limit has a maximum of 100. A developer adds a handler that doesn't enforce it. The client and server disagree about the contract, and nobody notices until a customer reports broken pagination.
We wanted a server-side story where your handler only contains business logic. All the parsing, validation, and error response generation come directly from the spec. If the spec changes, the handler's signature changes, and the compiler tells you what to fix.
corvusjson openapi-server petstore.json \
--rootNamespace Petstore.Server \
--outputPath ./Generated
dotnet add package Corvus.Text.Json.OpenApi
dotnet add package Corvus.Text.Json
You get:
IApiPetsHandler) - one async method per operation. This is the only thing you implement.MapApiEndpoints) - a single extension method that wires all routes with correct HTTP methods and path templates.This is the core principle. The generated middleware runs the full validation pipeline before your handler is called:
HTTP Request arrives
→ Parse path/query/header/cookie params
→ Validate against JSON Schema
→ Parse and validate request body
→ If anything is invalid: return 400 Problem Details
→ Your Handler runs (everything is guaranteed valid)
→ Validate response body, serialize, write HTTP
If a required parameter is missing, schema validation fails, or the body can't be parsed, the request never reaches your code. The generated middleware returns a properly formatted Problem Details response. Your handler only sees valid, typed data.
The setup is deliberately minimal:
using Corvus.Text.Json;
using Petstore.Server;
using Petstore.Server.Models;
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
WebApplication app = builder.Build();
PetsHandler handler = new();
app.MapApiEndpoints(handler);
app.Run();
MapApiEndpoints registers every route from the spec with the correct HTTP method and path template. You don't write app.MapGet(...) by hand. If the spec adds a new operation, the handler interface gains a new method, and the compiler tells you to implement it.
Here's what a handler looks like. Notice what's missing. You don't parse parameters, you don't validate schemas, and you don't handle protocol-level errors. You write business logic (including any business-logic errors you need to surface), and the generated infrastructure takes care of the rest:
internal sealed class PetsHandler : IApiPetsHandler
{
public ValueTask<ListPetsResult> HandleListPetsAsync(
ListPetsParams parameters,
JsonWorkspace workspace,
CancellationToken cancellationToken = default)
{
// parameters.Limit is already validated - guaranteed <= 100
ListPetsResult result = ListPetsResult.Ok(
body: new Pets.Source((ref Pets.Builder b) =>
{
b.AddItem(new Pet.Source((ref Pet.Builder pb) =>
{
pb.Create(id: 1, name: "Luna"u8, tag: "cat"u8);
}));
}),
workspace: workspace);
return new(result);
}
}
The JsonWorkspace provides pooled memory for building the response body. The Result factory methods mirror the spec's declared status codes. ListPetsResult.Ok(...) returns a 200, and CreatePetResult.Created(...) returns a 201. You can't accidentally return a 200 body with a 201 status.
Each operation gets a result type with factory methods matching the spec:
public ValueTask<CreatePetResult> HandleCreatePetAsync(
CreatePetParams parameters,
JsonWorkspace workspace,
CancellationToken cancellationToken = default)
{
// parameters.Body.Name is guaranteed present - schema says required
string name = (string)parameters.Body.Name;
return new(CreatePetResult.Created(
body: new Pet.Source((ref Pet.Builder pb) =>
{
pb.Create(id: 42, name: name.AsSpan(), tag: "dog"u8);
}),
workspace: workspace));
}
The generated code also validates your response before writing it. If your handler builds a response body that violates the output schema, you get a 500 in development. A silently malformed response does not reach clients.
In the [ref slug=openapi-code-generation-with-corvus-end-to-end text=next post], we'll wire both sides together - a generated client calling a generated server over real HTTP - and see how the contract guarantee works in practice.
I think that everyone who uses AI recognizes the following pattern; you ask an LLM a simple question and it answers like it's writing a blog post: introduction, context, three examples, a closing summary. Fine for a first read, expensive when you're chaining calls or running an agent loop all day.
The trick to avoid this is called "caveman prompting". You tell the model to drop articles, pleasantries and filler, and answer in short, blunt fragments. It sounds silly. But it works up to a point.
Most people's first instinct is a one-line system prompt:
Be concise. No fluff.
This already gets you a good chunk of the savings. In benchmarks I've seen floating around, a plain "be concise, return structured output" instruction accounts can already give you a nice reduction. It's the cheapest fix and most people stop here, which is reasonable.
The caveman skill takes this idea further and transform it into a token-saving solution. Just drop it as a skill/plugin into Claude Code, Copilot, Cursor, Codex, Gemini or one of a few dozen other agents. One install command:
npx skills add JuliusBrussee/caveman
The skill file tells the agent to drop articles, filler and pleasantries, answer in fragments, and use short synonyms ("big" instead of "extensive", "fix" instead of "implement a solution for"). Code, commands, error strings and symbols are explicitly left untouched, byte-for-byte.
It isn't all-or-nothing. There are several modes you switch between with a slash command:
/caveman lite drop filler and hedging, keep full sentences. Professional but tight. /caveman (default, "full") drop articles too, fragments are fine, short synonyms. /caveman ultra bare fragments, standard abbreviations (DB, auth, fn), arrows for causality. Remark: The caveman skill only shrinks what an agent says. If you want that it shrinks everything, have a look at the caveman-code skill.
I installed it on a few real sessions rather than trusting the README numbers. The reduction was real, but nowhere near the headline 65%. Depending on the task, I landed somewhere between 15% and 30% fewer tokens.
The variance made sense once I looked at what I was doing in each session. Short, back-and-forth debugging sessions barely moved the needle, the ~1-1.5k token overhead of the skill instruction itself was eating a good chunk of whatever it saved. Longer sessions with more explanatory answers, code reviews, architecture discussions, got closer to the 30% end.
Remark: I'd treat the 65% figure as a ceiling reached under fairly specific conditions, not a number to plan a budget around. If you're chaining a lot of short calls, measure it yourself before assuming the savings are there.
The author has built a small family of tools around the same idea: a full terminal coding agent that's caveman by default, a memory layer that stores session context compressed in the same grammar so it stays smaller across sessions, and even a fine-tuned model where the compression is baked into the weights instead of a system prompt. Worth a look if you're building agent-heavy workflows and the per-turn overhead of a text instruction actually matters to you.
Join members of the Visual Studio team to talk about what's new in the Visual Studio 2026 July Release.
Start Time: 2026-07-16 11:00 AM Pacific
Social: ["Visual Studio"]
🎙️ Featuring: Leslie Richardson, Andy Sterland, Mark Downie
#visualstudio #visualstudio2026
Apple has just released public betas for iOS 27 and other major OS updates that are set to publicly launch this fall. The big new feature this year is Siri AI, the delayed AI-powered revamp to Siri. It actually works - which is big praise! - though it keeps things brief.
Other betas available now include iPadOS 27, watchOS 27, and macOS 27 Golden Gate. If you want to test out Apple's upcoming updates, fair warning that you may run into issues like unexpected glitches or a battery that drains faster than you're used to. Use your best judgment on whether you should actually install the beta or wait to install an update until it's officially r …
In a series of campaigns observed between mid-2025 and mid-2026, Microsoft identified threat actor activity with overlapping tradecraft commonly associated with ShinyHunters, including voice phishing (vishing), supply chain compromise, and misconfigured guest access to target customer SaaS-based applications such as Salesforce instances. The threat actors abused trusted OAuth relationships for unauthorized access, data exfiltration, and persistence.
Three primary intrusion paths were observed including vishing techniques targeting OAuth consent, supply chain compromise through trusted workflows and integrations such as Salesloft and Gainsight, and exploitation of misconfigured guest access. Abuse of these access paths led to inherited user and application privileges, allowing successful enumeration and querying of customer relationship management (CRM) records while evading conventional authentication detections. These intrusion paths often led to persistent access and exfiltration of data at scale. This tradecraft highlights how a single entry point can rapidly expand to greater enterprise impacts.
Microsoft observed activity associated with these techniques in many tenants from various industries such as retail, education and manufacturing. These findings reinforce the importance of monitoring OAuth-connected applications, validating third-party integrations, reviewing guest access configurations, and enabling Salesforce event monitoring. Leveraging this data, Microsoft consulted with Salesforce to improve granularity in telemetry for Defender for Cloud Apps with near-real-time detection, offering connected application attribution and expanded application permission insights. This activity was not the result of a vulnerability inherent to Salesforce. Rather, the threat actors abused trusted OAuth relationships for unauthorized access, data exfiltration, and persistence.
Threat actor campaigns targeting Salesforce customers and using tradecraft associated with ShinyHunters pose a high-impact risk to sensitive data and downstream SaaS ecosystems. These campaigns abuse OAuth trust relationships to operate within pre-existing, legitimate workflows.

Observed activity can be grouped into three primary intrusion paths:
In campaigns beginning in mid-2025, the threat actors conducted vishing attacks impersonating IT support personnel. Threat actors socially engineered employees into authorizing attacker-controlled connected apps within their Salesforce tenant. In several confirmed cases, threat actors guided users through the OAuth consent workflow to grant access to a malicious application disguised as a legitimate Salesforce Data Loader tool. After users granted consent, these highly privileged OAuth applications enabled threat actors to perform API calls on behalf of the victim user, facilitating:
This intrusion path exploits the OAuth authorization flow of trusted SaaS services rather than relying on malware or credential replay. Threat actors exfiltrate data through sanctioned application access inherited from user privileges.
Following initial access campaigns, threat actors escalated into supply‑chain-driven attacks targeting third‑party SaaS vendors offering popular solutions that integrate with Salesforce, often using OAuth tokens. In August 2025, compromised Salesloft Drift credentials enabled attackers to obtain connection secrets used by downstream SaaS applications, enabling the use of OAuth tokens in multiple customer Salesforce instances.
A subsequent campaign in November 2025 targeted Gainsight-published applications integrated with Salesforce, allowing attackers to leverage trusted external connections to maintain persistent API access in multiple Salesforce customer instances. These activities often appeared indistinguishable from legitimate integration behavior. Threat actors performed discovery, bulk data queries, and mass exfiltration of sensitive CRM records, including accounts, contacts, and service case data, without generating traditional sign-in anomalies.
More recently, in June 2026, the market intelligence platform Klue experienced an incident where a threat actor, Storm-3138, gained access to its system. Credentials used to access Salesforce customer instances were used in the same fashion, to discover, query, and exfiltrate data.
Over recent months, Microsoft observed an increase in suspicious guest-user activity targeting Salesforce Aura endpoints across multiple organizations. In these incidents, threat actors leveraged unauthenticated access to Aura framework functionality and used GraphQL-based Aura requests to systematically query and retrieve data. While the activity did not exploit a software vulnerability, it took advantage of misconfigured guest-user permissions to gain unauthorized access to data. By chaining Aura requests and leveraging GraphQL queries, the actors were able to circumvent standard record-retrieval limitations and extract significantly larger volumes of data than would typically be accessible to guest users. All three intrusion paths relied on inheriting trusted application or user privileges, making malicious activity difficult to distinguish from normal operations. The resulting quiet persistence and large-scale data access highlight the need for stronger detection, visibility, and governance of OAuth-connected applications and guest user accounts.
For customers using Salesforce Shield: Event Monitoring, the upgraded Microsoft Defender for Cloud Apps Salesforce connector onboards the Real-Time Event Monitoring (RTEM) framework, enabling faster detection and investigation of Salesforce-based attacks.
Investigations into these campaigns exposed a recurring challenge for security teams: malicious activity often appeared indistinguishable from legitimate Salesforce usage because threat actors operated through trusted identities, approved OAuth applications, and authorized integrations. Traditional authentication-focused detections frequently provided limited visibility into the resulting application activity.
To improve investigation and detection of these scenarios, Microsoft expanded Salesforce visibility in Defender for Cloud Apps through additional event telemetry, connected application attribution, and enhanced application permissions insights. These capabilities help security teams identify suspicious OAuth activity, investigate potentially compromised integrations, and better understand how access was obtained and used within customer Salesforce instances.
Key capabilities include:
Together with Salesforce Shield: Event Monitoring, these capabilities help security teams investigate suspicious OAuth activity, validate the legitimacy of connected applications, and better understand the potential impact of a compromise.
While improved detection is critical, recent incidents have also highlighted the need for stronger preventive controls and ongoing governance of OAuth-connected applications. To address this, Microsoft Defender introduces new posture capabilities for connected and external client apps in Salesforce. Security teams can gain visibility into each OAuth app and its non-human identity, prioritize risk, and reduce the attack surface.
Microsoft Defender provides comprehensive visibility into all Salesforce-integrated connected and external client apps, including granted OAuth scopes and privileges.

Security teams often struggle to identify applications with powerful administrative or sensitive permissions. The highly privileged apps insight highlights applications that have been granted elevated scopes, enabling quick identification of apps that may pose significant risk.
Additionally, security teams can use permission-based filters to identify apps with specific high-risk scopes and validate whether such access is justified.

Organizations often create applications for temporary or one-time use, but those applications are rarely removed afterward. These unused apps continue to retain permissions, creating unnecessary exposure. With the recent changes, Defender now allows security teams to identify applications that have been inactive for extended periods (for example, 90 days or more), making it easy to review and revoke access where appropriate to reduce the attack surface.

To further streamline investigation and response, Defender introduces a comprehensive risk scoring model for connected applications. Each application is assigned a numerical risk score [0-100] based on multiple risk indicators, such as usage patterns, permission sensitivity, and behavioral signals. This allows security teams to prioritize efforts effectively and focus on applications that require immediate attention. Security teams can create custom policies based on risk thresholds to trigger alerts, actions, and notifications.

To further investigate the specific Non-Human identity risk details, the factors contributing to the risk score are available in Non-Human Identities Risk score tab.

Microsoft recommends the following mitigations to reduce the impact of this threat. Check the recommendations card for the deployment status of monitored mitigations.
Microsoft Defender customers can refer to the list of applicable detections including new detections powered by the upgraded Microsoft Defender for Cloud Apps Salesforce connector. Microsoft Defender coordinates detection, prevention, investigation, and response for endpoints, identities, email, and apps to provide integrated protection against attacks like the threat discussed in this blog.
Customers with provisioned access can also use Microsoft Security Copilot in Microsoft Defender to investigate and respond to incidents, hunt for threats, and protect their organization with relevant threat intelligence.
| Tactic | Observed activity | Microsoft Defender coverage |
| Initial Access | A user’s Salesforce session was hijacked and used | Salesforce detected a possibly hijacked user session |
| Credential Access | A user was the target of credential stuffing activity | Salesforce detected a successful credential stuffing attack |
| Lateral Movement | A user with a very high risk score is signing into Salesforce via SSO | Salesforce SSO sign-in by high-risk user |
| Collection / Exfiltration | API-heavy access, report export, and scraping patterns; potential multi-SaaS expansion depending on victim footprint. | – Possible Salesforce scraping activity – Salesforce detected a user performing anomalous API activity – Salesforce detected a user performing anomalous report activity |
| Collection / Exfiltration | Anomalous behavior from Salesforce Connected Apps | – Salesforce Connected App activity from a new IP address – Salesforce Connected App activity involving new – Salesforce entity Salesforce Connected App activity involving new endpoint(s) |
| Collection / Exfiltration | Guest user activity associated with the AuraInspector framework | Suspicious Salesforce Aura Activity |
| Collection / Exfiltration | Anomalous behavior from a guest user | Salesforce detected a guest user performing anomalous activity |
Microsoft customers can use the following reports in Microsoft products to get the most up-to-date information about the threat actor, malicious activity, and techniques discussed in this blog. These reports provide intelligence, protection information, and recommended actions to prevent, mitigate, or respond to associated threats found in customer Salesforce instances.
NOTE: The sample queries let you search one week of events. To inspect events and hunt for threat actor-related indicators over a longer period, go to the Advanced Hunting page > Query tab, and use the calendar dropdown to set the time range to Last 30 days (the maximum for raw data).
Hunt for Salesforce connected-app activity from suspicious infrastructure
CloudAppEvents
| where Application == "Salesforce"
| where ActionType in ("ApiTotalUsage", "API Event")
| extend ConnectedAppId = tostring(
coalesce(
RawEventData.CONNECTED_APP_ID, // from ApiTotalUsage
RawEventData.ConnectedAppId // from API Event
)
)
| where isnotempty(ConnectedAppId)
| where array_length(UncommonForUser) > 0 // at least 1 attribute is flagged as uncommon
Hunt for API activity associated with connected apps and relevant user ids
CloudAppEvents
| where Application == "Salesforce"
| where ActionType in ("ApiTotalUsage", "API Event")
| extend SalesforceUserId=coalesce(tostring(RawEventData.USER_ID), tostring(RawEventData.UserId))
| extend ConnectedAppName=tostring(RawEventData.CONNECTED_APP_NAME) // Connected App Name is not available on the ApiEvent event
| summarize count() by AccountObjectId, AccountId, AccountDisplayName, SalesforceUserId, IPAddress, UserAgent, ConnectedAppName
Hunt for anomalous report export / large data access
CloudAppEvents
| where Application == "Salesforce"
| where ActionType == "ReportExport"
| extend SalesforceUserId = tostring(RawEventData.USER_ID)
| summarize Events=count() by AccountObjectId, AccountId, AccountName, SalesforceUserId, IPAddress, UserAgent
Pivot from a suspicious connected app (name/id) to impacted users and actions
CloudAppEvents
| where Application == "Salesforce"
| where RawEventData has ""
| project Timestamp, AccountId, AccountDisplayName, ActionType, IPAddress, UserAgent, RawEventData
| order by Timestamp desc
Audit queries to verify what objects users are accessing
CloudAppEvents
| where Application == "Salesforce"
| where ActionType == "UniqueQuery"
| extend
QueryText = tostring(RawEventData.QUERY_IDENTIFIER), // Full query text
QueryObject = extract(@"(?i)\bfrom\s+([^\s]+)", 1, tostring(RawEventData.QUERY_IDENTIFIER)), // Extract just the target object
SalesforceUserId = tostring(RawEventData.USER_ID)
| where QueryText != "SOQL"
| project Timestamp, AccountDisplayName, SalesforceUserId, QueryObject, QueryText
Hunt for users with very high Defender risk score signing into Salesforce
let VeryRiskyUsers = IdentityInfo
| where DefenderRiskScoreNumber >= 90
| distinct AccountObjectId
CloudAppEvents
| where Application == "Salesforce"
| where ActionType has "sso" or ActionType has "saml"
| where AccountObjectId in (VeryRiskyUsers)
| project Timestamp, AccountObjectId, AccountDisplayName, ActionType, UserAgent
| order by Timestamp desc
| Indicator | Type | Description |
| 138.226.246.94 | IP address | Used by the Klue integration to call Salesforce API to perform CRM queries on June 11. Previously disclosed by Klue in their notification about the breach. |
| 212.86.125.24 | IP address | |
| 213.111.148.90 | IP address | |
| 94.154.32.160 | IP address | |
| 103.75.11.78 | IP address | Used to target the Aura framework with guest access from June 19 to 22. These IP addresses were not previously published and were discovered by Microsoft as part of a novel campaign. |
| 103.75.11.110 | IP address |
Initial Access
Persistence
Collection
Exfiltration
This research is provided by Microsoft Defender Security Research, Shruti Ranjit, Doug Cranston, Anand Deshpande, Ronen Rafaeli, and with contributions from members of Microsoft Threat Intelligence.
For the latest security research from the Microsoft Threat Intelligence community, check out the Microsoft Threat Intelligence Blog.
To get notified about new publications and to join discussions on social media, follow us on LinkedIn, X (formerly Twitter), and Bluesky.
To hear stories and insights from the Microsoft Threat Intelligence community about the ever-evolving threat landscape, listen to the Microsoft Threat Intelligence podcast.
Review our documentation to learn more about our real-time protection capabilities and see how to enable them within your organization.
The post Defending SaaS-based applications against ShinyHunters OAuth abuse appeared first on Microsoft Security Blog.