France's tax authority, the Direction Générale des Finances Publiques (DGFiP), has confirmed a data breach impacting approximately 680,000 individuals. The attackers did not exploit a zero-day, did not deploy sophisticated malware, and did not defeat perimeter defenses. They logged in. Using compromised credentials, the threat actors accessed a government portal containing personal and enterprise tax-related data — names, contact details, tax identifiers, and business information — and simply browsed and extracted what they wanted.
This is the breach pattern I have watched dominate incident response engagements for the past three years: valid account abuse. Whether the credentials came from a phishing kit, an infostealer log sold on Telegram, password reuse from an unrelated breach, or a compromised partner account, the outcome is identical — the attacker's activity is, by design, indistinguishable from legitimate user behavior at the authentication layer. The only place these intrusions become visible is in behavioral and contextual anomalies: where the login came from, what the account touched, and how much data it pulled.
If you operate any portal containing regulated personal data — tax records, health records, financial data — this breach is your tabletop scenario. Below is a practitioner-level breakdown of what happened, how to detect this attack class, and how to harden your environment against it.
Technical Analysis: Anatomy of a Valid-Account Intrusion
What Is Known
- Victim: DGFiP (Direction Générale des Finances Publiques), the French national tax administration
- Scale: ~680,000 individuals impacted
- Data exposed: Personal and enterprise tax-related data
- Initial access vector: Compromised credentials — the attackers authenticated as a legitimate user into a system holding tax data
- Exploitation status: Confirmed, in-the-wild, completed breach. This is not a theoretical vulnerability; the data was accessed and the authority has disclosed the incident publicly. No CVE is associated with this incident — there is no software bug to patch. The vulnerability was an unprotected or insufficiently protected identity.
The Attack Chain (Defender's View)
While DGFiP has not released granular forensic details, credential-based intrusions into government and financial portals follow a well-documented chain:
- Credential acquisition (T1078 — Valid Accounts, pre-stage): Credentials harvested via infostealer malware (RedLine, Lumma, Vidar-class stealers), phishing, credential stuffing against reused passwords, or purchase from initial access brokers.
- Authentication from anomalous context: Login from a foreign ASN, residential proxy, VPN exit node, or datacenter IP inconsistent with the legitimate user's profile — often outside business hours for the account's typical pattern.
- Reconnaissance and data access: The attacker navigates the portal, queries records, and enumerates available data. At the application layer this looks like a high volume of record lookups or report generation from a single session.
- Bulk access / exfiltration (T1530 — Data from Cloud Storage / T1213 — Data from Information Repositories): Mass retrieval of records — in this case, hundreds of thousands of taxpayer entries — either through the application's own export functionality or scripted sequential queries.
Why This Keeps Working
Three systemic failures make this attack class reliable:
- No phishing-resistant MFA. If the portal account relied on password-only authentication or phishable MFA (SMS, TOTP push-approved by a fatigued user), a stolen password equals full access. Government service accounts and partner/professional accounts (accountants, tax professionals with delegated access) are frequently the weakest link.
- No behavioral anomaly detection on the application layer. A single session querying thousands of taxpayer records is not normal for any legitimate workflow — yet most portals log this only in application logs that never reach a SIEM.
- Stale, over-privileged accounts. Professional/delegated-access accounts (e.g., accounting firms accessing client tax records) accumulate access far beyond what they need and are rarely reviewed.
The MITRE ATT&CK mapping for this intrusion class: T1078 (Valid Accounts), T1110 (Brute Force / Credential Stuffing, where applicable), T1557 (Adversary-in-the-Middle, if phishing-proxied MFA), T1213 (Data from Information Repositories), T1530 (Data from Cloud Storage).
Detection & Response
The detections below target the observable behaviors of valid-account abuse against portals and identity systems: anomalous authentication context, impossible travel, credential stuffing patterns, and bulk data access. Tune thresholds to your baseline — these are hunting rules, not set-and-forget alerts.
---
title: Impossible Travel Sign-In to Sensitive Portal
id: 3f8a1c92-7d4e-4b6a-9e21-5c0f2a8d1b47
status: experimental
description: Detects successful authentications to a sensitive web portal from two geographically distant locations within a short time window, consistent with compromised credential usage from a foreign or proxied location.
references:
- https://attack.mitre.org/techniques/T1078/
author: Security Arsenal
date: 2026/02/11
tags:
- attack.initial_access
- attack.t1078
logsource:
product: azure
service: signinlogs
detection:
selection:
OperationName: 'Sign-in activity'
Status: 0
condition: selection
falsepositives:
- Users on mobile networks switching egress points
- Corporate VPN with split egress
level: high
---
title: Authentication from Datacenter or Proxy ASN to User Portal
id: 9b2e7d41-1c3f-4a58-b864-2e9d5f0a6c83
status: experimental
description: Detects successful portal logins sourced from known datacenter, hosting, VPN exit-node, or residential proxy ASNs. Legitimate users of citizen/enterprise portals rarely authenticate from hosting providers; attackers route stolen-credential sessions through proxies to blend in.
references:
- https://attack.mitre.org/techniques/T1078/
- https://attack.mitre.org/techniques/T1090/
author: Security Arsenal
date: 2026/02/11
tags:
- attack.initial_access
- attack.t1078
- attack.command_and_control
- attack.t1090
logsource:
category: webserver
detection:
selection:
sc_status: 200
cs_method:
- 'POST'
cs_uri_stem|contains:
- '/login'
- '/auth'
- '/oauth'
- '/signin'
filter_known_hosts:
x_asn_org|contains:
- 'Amazon'
- 'Google Cloud'
- 'Microsoft Azure'
- 'OVH'
- 'Hetzner'
- 'DigitalOcean'
- 'M247'
- 'Datacamp'
condition: selection and filter_known_hosts
falsepositives:
- Automated monitoring or health-check services
- Legitimate API integrations from hosted infrastructure
level: medium
---
title: Credential Stuffing or Password Spray Against Portal Login Endpoint
id: 5d1f9a36-8b42-4e7c-a093-6f2c8b1d4e75
status: experimental
description: Detects high-volume failed authentication attempts against a web portal login endpoint from a single source or distributed sources, indicative of credential stuffing with breached password lists or password spraying.
references:
- https://attack.mitre.org/techniques/T1110/
author: Security Arsenal
date: 2026/02/11
tags:
- attack.credential_access
- attack.t1110.004
logsource:
category: webserver
detection:
selection:
cs_uri_stem|contains:
- '/login'
- '/auth'
- '/signin'
- '/oauth/token'
sc_status:
- 401
- 403
condition: selection | count(c_ip) by cs_uri_stem > 20
timeframe: 5m
falsepositives:
- Misconfigured client applications retrying authentication
- Shared corporate NAT egress inflating per-IP counts
level: high
// Hunt: Anomalous sign-in context + high-volume data access pattern
// Part 1: Successful sign-ins from new countries/ASNs for accounts accessing sensitive apps
let lookback = 14d;
let baseline = SigninLogs
| where TimeGenerated > ago(lookback)
| where ResultType == 0
| summarize Countries = make_set(Location), ASNs = make_set(NetworkLocationDetails) by UserPrincipalName;
SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0
| extend ASN = tostring(parse_json(NetworkLocationDetails).networkNames)
| join kind=leftanti (baseline) on UserPrincipalName, $left.Location == $right.Countries
| project TimeGenerated, UserPrincipalName, AppDisplayName, IPAddress, Location, ASN, DeviceDetail, UserAgent
| sort by TimeGenerated desc;
// Part 2: Single identity performing bulk record access in a short window (Defender for Cloud Apps / app audit ingestion)
CloudAppEvents
| where TimeGenerated > ago(24h)
| where ActionType in ("FileDownloaded", "FileAccessed", "ExportPerformed", "ReportGenerated") or ObjectType =~ "Record"
| summarize AccessCount = count(), DistinctObjects = dcount(ObjectId), Apps = make_set(Application) by AccountDisplayName, AccountObjectId, IPAddress, bin(TimeGenerated, 1h)
| where AccessCount > 500 or DistinctObjects > 200
| sort by AccessCount desc;
// Part 3: Password spray / stuffing pattern against Entra ID
SigninLogs
| where TimeGenerated > ago(1h)
| where ResultType in ("50126", "50055", "50057") // invalid creds, expired, disabled
| summarize FailedUsers = dcount(UserPrincipalName), Attempts = count(), TargetedApps = make_set(AppDisplayName) by IPAddress, bin(TimeGenerated, 5m)
| where FailedUsers > 10 or Attempts > 50
| sort by FailedUsers desc;
-- Hunt endpoints for infostealer artifacts that yield harvested credentials.
-- Infostealers (Lumma/RedLine/Vidar class) are a primary source of the
-- credentials used in valid-account breaches like the DGFiP intrusion.
-- Look for stealer access to browser credential stores and crypto wallet paths.
-- Part 1: Non-browser processes reading browser credential databases
SELECT Pid, Name, Exe, CommandLine, Username
FROM pslist()
WHERE CommandLine =~ '(?i)(Login Data|Cookies|Web Data|Local State|logins\.json|key4\.db)'
AND Exe !~ '(?i)(chrome|firefox|edge|brave|opera)\.exe'
AND Exe !~ '(?i)(Program Files.?(x86)?\\(Google|Microsoft|Mozilla))'
-- Part 2: Staged credential-store copies in temp/user-writable paths
SELECT FullPath, Size, Mtime
FROM glob(globs='C:\\Users\\*\\AppData\\Local\\Temp\\**')
WHERE FullPath =~ '(?i)(Login Data|cookies|passwords|credentials|wallet)'
AND Mtime > now() - 604800
# Audit and harden: identify accounts at risk of valid-account abuse
# Run with appropriate Graph / Entra permissions (AuditLog.Read.All, Policy.Read.All)
Connect-MgGraph -Scopes "AuditLog.Read.All","Policy.Read.All","Directory.Read.All"
# 1. Find users WITHOUT any MFA registered (prime credential-abuse targets)
$report = Get-MgReportAuthenticationMethodUserRegistrationDetail -All
$report | Where-Object { $_.IsMfaRegistered -eq $false } |
Select-Object UserPrincipalName, UserType, MethodsRegistered |
Export-Csv .\NoMFA_Accounts.csv -NoTypeInformation
Write-Output "Users without MFA exported to NoMFA_Accounts.csv"
# 2. List guest/partner accounts with sign-in activity in last 30 days (delegated access risk)
$cutoff = (Get-Date).AddDays(-30).ToString("yyyy-MM-ddTHH:mm:ssZ")
Get-MgAuditLogSignIn -Filter "createdDateTime ge $cutoff and userType eq 'Guest'" -All |
Group-Object UserPrincipalName |
Select-Object Name, Count |
Export-Csv .\GuestSignIns_30d.csv -NoTypeInformation
Write-Output "Guest sign-in summary exported to GuestSignIns_30d.csv"
# 3. Identify Conditional Access policies NOT enforcing phishing-resistant auth
Get-MgIdentityConditionalAccessPolicy -All |
Where-Object { $_.GrantControls.AuthenticationStrength -eq $null -and $_.State -eq 'enabled' } |
Select-Object DisplayName, Id, State |
Format-Table -AutoSize
Write-Output "Review the above CA policies: enforce authentication strengths (FIDO2/passkeys) for sensitive apps."
# 4. Flag stale accounts: enabled, no sign-in for 90+ days, still holding access
Get-MgUser -All -Property SignInActivity,AccountEnabled,UserPrincipalName |
Where-Object { $_.AccountEnabled -eq $true -and
$_.SignInActivity.LastSignInDateTime -lt (Get-Date).AddDays(-90) } |
Select-Object UserPrincipalName, @{n='LastSignIn';e={$_.SignInActivity.LastSignInDateTime}} |
Export-Csv .\Stale_Enabled_Accounts.csv -NoTypeInformation
Write-Output "Stale enabled accounts exported - review and disable."
Remediation: Closing the Valid-Account Gap
There is no patch for "the attacker knew the password." Remediation is architectural and procedural. Prioritize in this order:
1. Enforce Phishing-Resistant MFA — Immediately
- Move all accounts with access to sensitive/regulated data to FIDO2 passkeys, Windows Hello for Business, or certificate-based authentication. TOTP and push MFA remain phishable via adversary-in-the-middle kits and MFA fatigue.
- Eliminate SMS-based MFA for any privileged or data-bearing role.
- For portals serving external users (citizens, businesses, delegated professionals like the accountants/tax advisors in the DGFiP ecosystem), require MFA enrollment and step-up authentication for bulk data views or exports.
2. Deploy Risk-Based Conditional Access
- Block or challenge sign-ins from anonymous proxies, TOR, datacenter ASNs, and unfamiliar geographies using Entra ID Protection risk policies (or equivalent in Okta/Ping).
- Require compliant/managed devices for administrative and professional delegated-access accounts.
- Apply token theft protections: Continuous Access Evaluation (CAE) and token binding so a replayed session token is useless off-device.
3. Instrument the Application Layer — Not Just the Perimeter
- Stream portal/application audit logs to your SIEM. Alert on per-session and per-day record access volume (e.g., a single account viewing >N taxpayer/customer records in an hour). The DGFiP breach involved access to hundreds of thousands of records; a rate-based application alert is the single highest-fidelity detection for this pattern.
- Alert on first-use of export/bulk-report functionality by any account.
- Implement query throttling and hard caps on records retrievable per session for non-API human users.
4. Credential Hygiene and Exposure Monitoring
- Monitor haveibeenpwned-style breach corpora and infostealer log markets for credentials matching your domain. Reset exposed passwords before they are used, not after.
- Enforce banned-password lists and check new passwords against known-compromised lists (Entra Password Protection / equivalent).
- Audit for password reuse between the breached ecosystem (partners, contractors, professional portals) and your own systems.
5. Account Lifecycle and Delegated Access Governance
- Review all delegated/professional access accounts quarterly; disable stale accounts (script above, step 4).
- Apply least privilege to delegated roles: a tax professional should see only their clients' records, and your application should enforce that server-side, not by UI filtering.
6. Breach Response Obligations
- Under GDPR, a breach of this scale requires CNIL notification within 72 hours and direct notification to affected individuals where risk is high. DGFiP's disclosure follows this framework; ensure your own IR plan has GDPR/CCPA/state notification workflows pre-drafted.
- Preserve authentication and application logs immediately upon suspicion — in credential-abuse cases, application logs are often the only forensic evidence of scope (which records were viewed). Without them, you cannot bound the breach, which inflates notification scope and regulatory exposure.
If You Suspect You're the Next DGFiP
- Force password resets on the affected account population and revoke all sessions/refresh tokens.
- Review 90 days of authentication and application access logs for anomalous geographies, ASNs, and access volumes.
- Engage your IR retainer for scoping — do not attempt to bound a records-access breach with perimeter logs alone.
The lesson from France is uncomfortable but clear: identity is the perimeter, and if your detection strategy ends at the login page, an attacker with a stolen password owns your data with your own blessing. Behavioral detection on post-authentication activity is no longer optional for any system holding regulated data.
Related Resources
Security Arsenal Incident Response Services AlertMonitor Platform Book a SOC Assessment incident-response Intel Hub
Is your security operations ready?
Get a free SOC assessment or see how AlertMonitor cuts through alert noise with automated triage.