sync: Auto-sync from Mikes-MacBook-Air.local at 2026-03-09 08:14:13
Synced files: - Session logs updated - Latest context and credentials - Command/directive updates Machine: Mikes-MacBook-Air.local Timestamp: 2026-03-09 08:14:13 Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
404
temp/m365_security_scan.py
Normal file
404
temp/m365_security_scan.py
Normal file
@@ -0,0 +1,404 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
M365 Security Scan - Check all accounts for compromise indicators
|
||||
Scans: Sign-in logs, inbox rules, OAuth grants, MFA methods, forwarding
|
||||
"""
|
||||
|
||||
import requests
|
||||
import json
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
# Claude-MSP-Access Multi-Tenant App
|
||||
CLIENT_ID = "fabb3421-8b34-484b-bc17-e46de9703418"
|
||||
CLIENT_SECRET = "~QJ8Q~NyQSs4OcGqHZyPrA2CVnq9KBfKiimntbMO"
|
||||
|
||||
TENANTS = {
|
||||
"Valley Wide Plastering": {
|
||||
"tenant_id": "5c53ae9f-7071-4248-b834-8685b646450f",
|
||||
"domain": "valleywideplastering.com"
|
||||
},
|
||||
"BG Builders LLC": {
|
||||
"tenant_id": "ededa4fb-f6eb-4398-851d-5eb3e11fab27",
|
||||
"domain": "bgbuildersllc.com"
|
||||
}
|
||||
}
|
||||
|
||||
# Known suspicious patterns
|
||||
SUSPICIOUS_RULE_PATTERNS = [".", "..", "...", "spam", "junk", "filter"]
|
||||
SUSPICIOUS_OAUTH_APPS = ["gmail", "yahoo", "p2p", "autoforward"]
|
||||
US_COUNTRY_CODES = ["US", "United States"]
|
||||
|
||||
def get_token(tenant_id):
|
||||
"""Get Graph API access token for tenant"""
|
||||
url = f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token"
|
||||
data = {
|
||||
"client_id": CLIENT_ID,
|
||||
"client_secret": CLIENT_SECRET,
|
||||
"scope": "https://graph.microsoft.com/.default",
|
||||
"grant_type": "client_credentials"
|
||||
}
|
||||
resp = requests.post(url, data=data)
|
||||
if resp.status_code == 200:
|
||||
return resp.json().get("access_token")
|
||||
else:
|
||||
print(f" [ERROR] Token failed: {resp.status_code} - {resp.text[:200]}")
|
||||
return None
|
||||
|
||||
def graph_get(token, endpoint, params=None):
|
||||
"""Make Graph API GET request"""
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
url = f"https://graph.microsoft.com/v1.0{endpoint}"
|
||||
resp = requests.get(url, headers=headers, params=params)
|
||||
if resp.status_code == 200:
|
||||
return resp.json()
|
||||
elif resp.status_code == 404:
|
||||
return None
|
||||
else:
|
||||
return {"error": resp.status_code, "message": resp.text[:200]}
|
||||
|
||||
def graph_get_beta(token, endpoint, params=None):
|
||||
"""Make Graph API beta GET request"""
|
||||
headers = {"Authorization": f"Bearer {token}"}
|
||||
url = f"https://graph.microsoft.com/beta{endpoint}"
|
||||
resp = requests.get(url, headers=headers, params=params)
|
||||
if resp.status_code == 200:
|
||||
return resp.json()
|
||||
elif resp.status_code == 404:
|
||||
return None
|
||||
else:
|
||||
return {"error": resp.status_code, "message": resp.text[:200]}
|
||||
|
||||
def check_signin_logs(token, user_id, user_email, days=30):
|
||||
"""Check sign-in logs for foreign/suspicious IPs"""
|
||||
issues = []
|
||||
cutoff = (datetime.utcnow() - timedelta(days=days)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||
|
||||
# Get sign-in logs
|
||||
params = {
|
||||
"$filter": f"userId eq '{user_id}' and createdDateTime ge {cutoff}",
|
||||
"$top": 100,
|
||||
"$orderby": "createdDateTime desc"
|
||||
}
|
||||
result = graph_get_beta(token, "/auditLogs/signIns", params)
|
||||
|
||||
if result and "value" in result:
|
||||
foreign_logins = []
|
||||
failed_foreign = []
|
||||
|
||||
for signin in result["value"]:
|
||||
location = signin.get("location", {})
|
||||
country = location.get("countryOrRegion", "Unknown")
|
||||
status = signin.get("status", {})
|
||||
error_code = status.get("errorCode", 0)
|
||||
ip = signin.get("ipAddress", "Unknown")
|
||||
|
||||
if country not in US_COUNTRY_CODES and country != "Unknown":
|
||||
entry = {
|
||||
"ip": ip,
|
||||
"country": country,
|
||||
"city": location.get("city", "Unknown"),
|
||||
"time": signin.get("createdDateTime"),
|
||||
"success": error_code == 0,
|
||||
"error": error_code
|
||||
}
|
||||
if error_code == 0:
|
||||
foreign_logins.append(entry)
|
||||
else:
|
||||
failed_foreign.append(entry)
|
||||
|
||||
if foreign_logins:
|
||||
issues.append({
|
||||
"type": "FOREIGN_SUCCESS_LOGIN",
|
||||
"severity": "CRITICAL",
|
||||
"count": len(foreign_logins),
|
||||
"details": foreign_logins[:5] # Top 5
|
||||
})
|
||||
|
||||
if failed_foreign:
|
||||
# Group by country
|
||||
countries = list(set([f["country"] for f in failed_foreign]))
|
||||
issues.append({
|
||||
"type": "FOREIGN_FAILED_ATTEMPTS",
|
||||
"severity": "INFO",
|
||||
"count": len(failed_foreign),
|
||||
"countries": countries
|
||||
})
|
||||
elif result and "error" in result:
|
||||
if result["error"] != 404:
|
||||
issues.append({"type": "SIGNIN_LOG_ERROR", "severity": "WARNING", "details": result})
|
||||
|
||||
return issues
|
||||
|
||||
def check_inbox_rules(token, user_id, user_email):
|
||||
"""Check for malicious inbox rules"""
|
||||
issues = []
|
||||
result = graph_get(token, f"/users/{user_id}/mailFolders/inbox/messageRules")
|
||||
|
||||
if result and "value" in result:
|
||||
for rule in result["value"]:
|
||||
name = rule.get("displayName", "")
|
||||
is_enabled = rule.get("isEnabled", False)
|
||||
|
||||
# Check for suspicious patterns
|
||||
suspicious = False
|
||||
reasons = []
|
||||
|
||||
# Short/dot names
|
||||
if name in SUSPICIOUS_RULE_PATTERNS or len(name) <= 2:
|
||||
suspicious = True
|
||||
reasons.append(f"Suspicious name: '{name}'")
|
||||
|
||||
# Rules that delete/move and mark read
|
||||
actions = rule.get("actions", {})
|
||||
if actions.get("markAsRead") and (actions.get("delete") or actions.get("moveToFolder")):
|
||||
suspicious = True
|
||||
reasons.append("Marks read + moves/deletes")
|
||||
|
||||
# Stop processing
|
||||
if actions.get("stopProcessingRules") and (actions.get("moveToFolder") or actions.get("delete")):
|
||||
suspicious = True
|
||||
reasons.append("Stops processing + hides mail")
|
||||
|
||||
# Forwarding rules
|
||||
if actions.get("forwardTo") or actions.get("forwardAsAttachmentTo") or actions.get("redirectTo"):
|
||||
forward_targets = actions.get("forwardTo", []) + actions.get("forwardAsAttachmentTo", []) + actions.get("redirectTo", [])
|
||||
suspicious = True
|
||||
reasons.append(f"Forwards to external: {forward_targets}")
|
||||
|
||||
if suspicious and is_enabled:
|
||||
issues.append({
|
||||
"type": "SUSPICIOUS_INBOX_RULE",
|
||||
"severity": "CRITICAL",
|
||||
"rule_name": name,
|
||||
"rule_id": rule.get("id"),
|
||||
"reasons": reasons
|
||||
})
|
||||
elif result and "error" in result:
|
||||
if result["error"] != 404:
|
||||
issues.append({"type": "INBOX_RULE_ERROR", "severity": "WARNING", "details": result})
|
||||
|
||||
return issues
|
||||
|
||||
def check_oauth_grants(token, user_id, user_email):
|
||||
"""Check for suspicious OAuth app grants"""
|
||||
issues = []
|
||||
result = graph_get(token, f"/users/{user_id}/oauth2PermissionGrants")
|
||||
|
||||
if result and "value" in result:
|
||||
for grant in result["value"]:
|
||||
client_id = grant.get("clientId", "")
|
||||
scope = grant.get("scope", "")
|
||||
|
||||
# Get app details
|
||||
app_result = graph_get(token, f"/servicePrincipals/{client_id}")
|
||||
app_name = app_result.get("displayName", "Unknown") if app_result else "Unknown"
|
||||
|
||||
# Check for suspicious apps
|
||||
suspicious = False
|
||||
for pattern in SUSPICIOUS_OAUTH_APPS:
|
||||
if pattern.lower() in app_name.lower():
|
||||
suspicious = True
|
||||
break
|
||||
|
||||
# Check for sensitive scopes
|
||||
sensitive_scopes = ["Mail.ReadWrite", "Mail.Send", "MailboxSettings", "full_access"]
|
||||
has_sensitive = any(s.lower() in scope.lower() for s in sensitive_scopes)
|
||||
|
||||
if suspicious or (has_sensitive and "Microsoft" not in app_name):
|
||||
issues.append({
|
||||
"type": "SUSPICIOUS_OAUTH_APP",
|
||||
"severity": "HIGH" if suspicious else "MEDIUM",
|
||||
"app_name": app_name,
|
||||
"client_id": client_id,
|
||||
"scope": scope
|
||||
})
|
||||
|
||||
return issues
|
||||
|
||||
def check_mfa_methods(token, user_id, user_email):
|
||||
"""Check MFA methods for suspicious devices"""
|
||||
issues = []
|
||||
result = graph_get(token, f"/users/{user_id}/authentication/methods")
|
||||
|
||||
if result and "value" in result:
|
||||
methods = []
|
||||
for method in result["value"]:
|
||||
method_type = method.get("@odata.type", "")
|
||||
if "phone" in method_type.lower():
|
||||
phone = method.get("phoneNumber", "Unknown")
|
||||
methods.append({"type": "phone", "value": phone})
|
||||
elif "microsoftAuthenticator" in method_type:
|
||||
device = method.get("displayName", method.get("deviceTag", "Unknown"))
|
||||
methods.append({"type": "authenticator", "device": device})
|
||||
elif "fido2" in method_type.lower():
|
||||
methods.append({"type": "fido2", "model": method.get("model", "Unknown")})
|
||||
|
||||
# Flag if multiple authenticator devices (potential attacker device)
|
||||
auth_devices = [m for m in methods if m.get("type") == "authenticator"]
|
||||
if len(auth_devices) > 2:
|
||||
issues.append({
|
||||
"type": "MULTIPLE_AUTH_DEVICES",
|
||||
"severity": "MEDIUM",
|
||||
"count": len(auth_devices),
|
||||
"devices": auth_devices
|
||||
})
|
||||
|
||||
return issues
|
||||
|
||||
def check_mailbox_settings(token, user_id, user_email):
|
||||
"""Check mailbox for forwarding/auto-replies"""
|
||||
issues = []
|
||||
result = graph_get(token, f"/users/{user_id}/mailboxSettings")
|
||||
|
||||
if result and "error" not in result:
|
||||
# Check auto-forwarding
|
||||
# Note: Graph API doesn't expose SMTP forwarding directly, need Exchange
|
||||
|
||||
# Check automatic replies
|
||||
auto_reply = result.get("automaticRepliesSetting", {})
|
||||
if auto_reply.get("status") == "alwaysEnabled":
|
||||
issues.append({
|
||||
"type": "AUTO_REPLY_ALWAYS_ON",
|
||||
"severity": "LOW",
|
||||
"message": auto_reply.get("internalReplyMessage", "")[:100]
|
||||
})
|
||||
|
||||
return issues
|
||||
|
||||
def scan_tenant(tenant_name, tenant_info):
|
||||
"""Scan all users in a tenant"""
|
||||
print(f"\n{'='*60}")
|
||||
print(f"Scanning: {tenant_name}")
|
||||
print(f"Tenant ID: {tenant_info['tenant_id']}")
|
||||
print(f"{'='*60}")
|
||||
|
||||
token = get_token(tenant_info["tenant_id"])
|
||||
if not token:
|
||||
return {"error": "Failed to get token - admin consent may be needed"}
|
||||
|
||||
# Get all users
|
||||
users_result = graph_get(token, "/users", {"$select": "id,displayName,mail,userPrincipalName,accountEnabled"})
|
||||
if not users_result or "value" not in users_result:
|
||||
return {"error": f"Failed to get users: {users_result}"}
|
||||
|
||||
users = users_result["value"]
|
||||
print(f"Found {len(users)} users")
|
||||
|
||||
results = {
|
||||
"tenant": tenant_name,
|
||||
"scan_time": datetime.utcnow().isoformat(),
|
||||
"total_users": len(users),
|
||||
"clean_users": [],
|
||||
"flagged_users": [],
|
||||
"disabled_users": [],
|
||||
"errors": []
|
||||
}
|
||||
|
||||
for user in users:
|
||||
user_id = user.get("id")
|
||||
email = user.get("mail") or user.get("userPrincipalName", "Unknown")
|
||||
name = user.get("displayName", "Unknown")
|
||||
enabled = user.get("accountEnabled", True)
|
||||
|
||||
if not enabled:
|
||||
results["disabled_users"].append({"name": name, "email": email})
|
||||
print(f" [SKIP] {name} - disabled")
|
||||
continue
|
||||
|
||||
print(f" Checking: {name} ({email})...", end=" ")
|
||||
|
||||
all_issues = []
|
||||
|
||||
# Run all checks
|
||||
try:
|
||||
all_issues.extend(check_signin_logs(token, user_id, email))
|
||||
except Exception as e:
|
||||
results["errors"].append({"user": email, "check": "signin_logs", "error": str(e)})
|
||||
|
||||
try:
|
||||
all_issues.extend(check_inbox_rules(token, user_id, email))
|
||||
except Exception as e:
|
||||
results["errors"].append({"user": email, "check": "inbox_rules", "error": str(e)})
|
||||
|
||||
try:
|
||||
all_issues.extend(check_oauth_grants(token, user_id, email))
|
||||
except Exception as e:
|
||||
results["errors"].append({"user": email, "check": "oauth_grants", "error": str(e)})
|
||||
|
||||
try:
|
||||
all_issues.extend(check_mfa_methods(token, user_id, email))
|
||||
except Exception as e:
|
||||
results["errors"].append({"user": email, "check": "mfa_methods", "error": str(e)})
|
||||
|
||||
try:
|
||||
all_issues.extend(check_mailbox_settings(token, user_id, email))
|
||||
except Exception as e:
|
||||
results["errors"].append({"user": email, "check": "mailbox_settings", "error": str(e)})
|
||||
|
||||
# Categorize by severity
|
||||
critical = [i for i in all_issues if i.get("severity") == "CRITICAL"]
|
||||
high = [i for i in all_issues if i.get("severity") == "HIGH"]
|
||||
|
||||
if critical or high:
|
||||
results["flagged_users"].append({
|
||||
"name": name,
|
||||
"email": email,
|
||||
"user_id": user_id,
|
||||
"issues": all_issues
|
||||
})
|
||||
print(f"[FLAGGED] {len(critical)} critical, {len(high)} high")
|
||||
else:
|
||||
results["clean_users"].append({"name": name, "email": email})
|
||||
info_issues = [i for i in all_issues if i.get("severity") == "INFO"]
|
||||
if info_issues:
|
||||
print(f"[OK] ({len(info_issues)} info)")
|
||||
else:
|
||||
print("[OK]")
|
||||
|
||||
return results
|
||||
|
||||
def main():
|
||||
print("M365 Security Scan")
|
||||
print(f"Started: {datetime.utcnow().isoformat()}")
|
||||
|
||||
all_results = {}
|
||||
|
||||
for tenant_name, tenant_info in TENANTS.items():
|
||||
try:
|
||||
results = scan_tenant(tenant_name, tenant_info)
|
||||
all_results[tenant_name] = results
|
||||
except Exception as e:
|
||||
all_results[tenant_name] = {"error": str(e)}
|
||||
print(f" [ERROR] Tenant scan failed: {e}")
|
||||
|
||||
# Save results
|
||||
output_file = "/Users/azcomputerguru/ClaudeTools/temp/m365_security_scan_results.json"
|
||||
with open(output_file, "w") as f:
|
||||
json.dump(all_results, f, indent=2)
|
||||
|
||||
# Print summary
|
||||
print("\n" + "="*60)
|
||||
print("SCAN SUMMARY")
|
||||
print("="*60)
|
||||
|
||||
for tenant_name, results in all_results.items():
|
||||
print(f"\n{tenant_name}:")
|
||||
if "error" in results:
|
||||
print(f" [ERROR] {results['error']}")
|
||||
else:
|
||||
print(f" Total users: {results['total_users']}")
|
||||
print(f" Clean: {len(results['clean_users'])}")
|
||||
print(f" Flagged: {len(results['flagged_users'])}")
|
||||
print(f" Disabled: {len(results['disabled_users'])}")
|
||||
|
||||
if results["flagged_users"]:
|
||||
print("\n FLAGGED ACCOUNTS:")
|
||||
for user in results["flagged_users"]:
|
||||
print(f" - {user['name']} ({user['email']})")
|
||||
for issue in user["issues"]:
|
||||
print(f" [{issue['severity']}] {issue['type']}")
|
||||
|
||||
print(f"\nResults saved to: {output_file}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
274
temp/m365_security_scan_results.json
Normal file
274
temp/m365_security_scan_results.json
Normal file
@@ -0,0 +1,274 @@
|
||||
{
|
||||
"Valley Wide Plastering": {
|
||||
"tenant": "Valley Wide Plastering",
|
||||
"scan_time": "2026-03-06T01:21:31.514321",
|
||||
"total_users": 33,
|
||||
"clean_users": [
|
||||
{
|
||||
"name": "Adolfo Suarez",
|
||||
"email": "adolfos@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Toni",
|
||||
"email": "billing@valleywideplastering.onmicrosoft.com"
|
||||
},
|
||||
{
|
||||
"name": "Brian",
|
||||
"email": "Brian@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Carlos Reyes",
|
||||
"email": "carlos@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Charlie Jones",
|
||||
"email": "charlie@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Chris Guerrero",
|
||||
"email": "chris@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Customer Service",
|
||||
"email": "customerservice@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Customer Service",
|
||||
"email": "customerservice@valleywideplastering.onmicrosoft.com"
|
||||
},
|
||||
{
|
||||
"name": "Bart Graffin",
|
||||
"email": "estimating@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Fax Inbox",
|
||||
"email": "faxinbox@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Fermin Matta",
|
||||
"email": "fermin@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Francisco Arias",
|
||||
"email": "franciscoa@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "VWP Insurance",
|
||||
"email": "insurance@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Issac Chavez",
|
||||
"email": "isaacc@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "JR Guerrero",
|
||||
"email": "j-r@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Jaime Hernandez",
|
||||
"email": "jaimebh@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Jesse Guerrero",
|
||||
"email": "jesse@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "JR Guerrero",
|
||||
"email": "jr@CASARICA.NET"
|
||||
},
|
||||
{
|
||||
"name": "Juan Leal",
|
||||
"email": "juan@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Kayla Guerrero",
|
||||
"email": "kayla@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Orders VWP",
|
||||
"email": "orders@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Payroll VWP",
|
||||
"email": "payroll@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Ron Winger",
|
||||
"email": "ron@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Rose Guerrero",
|
||||
"email": "rose@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Ryan Guerrero",
|
||||
"email": "ryan@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Sammy Montijo",
|
||||
"email": "sammy@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Shelly Dooley",
|
||||
"email": "shelly@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Spro VWP",
|
||||
"email": "spro@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Computer Guru",
|
||||
"email": "sysadmin@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Teresa Carpio",
|
||||
"email": "teresa@valleywideplastering.com"
|
||||
},
|
||||
{
|
||||
"name": "Ty Fetters",
|
||||
"email": "Ty@CASARICA.NET"
|
||||
}
|
||||
],
|
||||
"flagged_users": [
|
||||
{
|
||||
"name": "Accounts Payable",
|
||||
"email": "acctpay@valleywideplastering.com",
|
||||
"user_id": "e70d7ec5-72f3-4b80-9614-e6bd5380b773",
|
||||
"issues": [
|
||||
{
|
||||
"type": "SUSPICIOUS_INBOX_RULE",
|
||||
"severity": "CRITICAL",
|
||||
"rule_name": "Order Acknowledgment ",
|
||||
"rule_id": "AQAAANfcAXQ=",
|
||||
"reasons": [
|
||||
"Stops processing + hides mail"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Billing Clerk",
|
||||
"email": "billing@valleywideplastering.com",
|
||||
"user_id": "4f708b80-e537-4f63-92d3-5feedfa28244",
|
||||
"issues": [
|
||||
{
|
||||
"type": "FOREIGN_FAILED_ATTEMPTS",
|
||||
"severity": "INFO",
|
||||
"count": 15,
|
||||
"countries": [
|
||||
"GN",
|
||||
"SG",
|
||||
"ID",
|
||||
"CZ",
|
||||
"CN",
|
||||
"BR",
|
||||
"IT",
|
||||
"ZA",
|
||||
"VN",
|
||||
"PH",
|
||||
"CA",
|
||||
"AR",
|
||||
"AL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "SUSPICIOUS_INBOX_RULE",
|
||||
"severity": "CRITICAL",
|
||||
"rule_name": "Tim Wolf",
|
||||
"rule_id": "AQAAAFDUDZY=",
|
||||
"reasons": [
|
||||
"Stops processing + hides mail"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "SUSPICIOUS_INBOX_RULE",
|
||||
"severity": "CRITICAL",
|
||||
"rule_name": "donotreply@pulte.com",
|
||||
"rule_id": "AQAAADPeesE=",
|
||||
"reasons": [
|
||||
"Stops processing + hides mail"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "SUSPICIOUS_INBOX_RULE",
|
||||
"severity": "CRITICAL",
|
||||
"rule_name": "ssrs-donotreply@pulte.com",
|
||||
"rule_id": "AQAAADJQZww=",
|
||||
"reasons": [
|
||||
"Stops processing + hides mail"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"disabled_users": [],
|
||||
"errors": []
|
||||
},
|
||||
"BG Builders LLC": {
|
||||
"tenant": "BG Builders LLC",
|
||||
"scan_time": "2026-03-06T01:54:05.702139",
|
||||
"total_users": 14,
|
||||
"clean_users": [
|
||||
{
|
||||
"name": "Accounting",
|
||||
"email": "Accounting@sonorangreenllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Accounts Payable",
|
||||
"email": "accountspayable@sonorangreenllc.com"
|
||||
},
|
||||
{
|
||||
"name": "admin",
|
||||
"email": "admin@bgbuildersllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Balynda Western",
|
||||
"email": "balynda@bgbuildersllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Barry Walling",
|
||||
"email": "barry@bgbuildersllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Barry Walling",
|
||||
"email": "Barry@sonorangreenllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Chad Bradford",
|
||||
"email": "chad@bgbuildersllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Lesley Roth",
|
||||
"email": "lesley@bgbuildersllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Projects",
|
||||
"email": "projects@bgbuildersllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Raul Flores",
|
||||
"email": "raul@bgbuildersllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Shelly Dooley",
|
||||
"email": "Shelly@bgbuildersllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Site Operations",
|
||||
"email": "siteoperations@bgbuildersllc.com"
|
||||
},
|
||||
{
|
||||
"name": "Computer Guru",
|
||||
"email": "sysadmin@bgbuildersllc.com"
|
||||
}
|
||||
],
|
||||
"flagged_users": [],
|
||||
"disabled_users": [
|
||||
{
|
||||
"name": "Shaun Smith",
|
||||
"email": "Shaun@bgbuildersllc.com"
|
||||
}
|
||||
],
|
||||
"errors": []
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user