<?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: Cyberlords Security</title>
    <description>The latest articles on DEV Community by Cyberlords Security (@cyberlords).</description>
    <link>https://dev.to/cyberlords</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%2F4217790%2F393215cd-a61d-4750-a3b6-a838714f58c5.png</url>
      <title>DEV Community: Cyberlords Security</title>
      <link>https://dev.to/cyberlords</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cyberlords"/>
    <language>en</language>
    <item>
      <title>Was your Instagram actually accessed? The evidence checklist before you pay anyone</title>
      <dc:creator>Cyberlords Security</dc:creator>
      <pubDate>Fri, 30 Oct 2026 17:53:23 +0000</pubDate>
      <link>https://dev.to/cyberlords/was-your-instagram-actually-accessed-the-evidence-checklist-before-you-pay-anyone-1mmf</link>
      <guid>https://dev.to/cyberlords/was-your-instagram-actually-accessed-the-evidence-checklist-before-you-pay-anyone-1mmf</guid>
      <description>&lt;p&gt;A "someone has been in my account" report is usually a mix of real artefacts and anxiety. The useful work is separating them: what the account actually records, what it doesn't, and what a forensic examiner can still recover.&lt;/p&gt;

&lt;p&gt;This is the checklist we run before anyone spends money on recovery — written for account owners, not for intruders.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Start with the record the platform keeps for you
&lt;/h2&gt;

&lt;p&gt;Instagram and Facebook both keep a login history. In the app: &lt;strong&gt;Settings → Accounts Centre → Password and security → Where you're logged in&lt;/strong&gt;. On the web: &lt;strong&gt;Settings → Login activity&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You are looking for a device, city or time you don't recognise. Two warnings:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;VPN users get false positives.&lt;/strong&gt; If you or your household use a VPN, a foreign city is expected.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The list is pruned.&lt;/strong&gt; Logins fall off after a while, so absence of a strange entry proves nothing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Screenshot it with a timestamp before you change anything. If the case later goes to a lawyer or the police, that screenshot is evidence and the account state is not.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Pull the data export, not just the activity page
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Accounts Centre → Your information and permissions → Download your information.&lt;/strong&gt; Choose JSON, and ask for the full date range.&lt;/p&gt;

&lt;p&gt;The export includes things the UI hides: IP addresses attached to sessions, message metadata, and the security emails the platform says it sent you. Those emails are the useful part — if the platform claims it sent a "new login" alert and you never received it, that tells you something about the intruder's access to your mailbox.&lt;/p&gt;

&lt;p&gt;The export takes hours to days. Request it first, then keep working.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Read your own mailbox for the handover trail
&lt;/h2&gt;

&lt;p&gt;An account takeover almost always leaves mail:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;password reset requests you didn't make (the "we sent you a code" mails),&lt;/li&gt;
&lt;li&gt;a "your email was changed" notice,&lt;/li&gt;
&lt;li&gt;security alerts marked read that you never opened.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Check the read/unread state.&lt;/strong&gt; An attacker with mailbox access marks their own alerts as read so the phone never buzzes. Unread alerts you don't remember seeing are normal; &lt;em&gt;read&lt;/em&gt; alerts from a night you were asleep are not.&lt;/p&gt;

&lt;p&gt;Also check for filters and forwarding rules — a rule that silently forwards password resets to another address is the single most-missed artefact in these cases.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Check the devices that are still attached
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Two-factor method.&lt;/strong&gt; If it changed from SMS to an authenticator you didn't set up, that's a strong indicator. So is a new backup code set.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linked apps.&lt;/strong&gt; Settings → Website permissions / Apps and websites. Anything you don't recognise had an access token; revoking it is reversible, deleting the account is not.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Trusted devices.&lt;/strong&gt; On Android, check for device admin apps you didn't install.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  5. Separate "accessed" from "still has access"
&lt;/h2&gt;

&lt;p&gt;These need different responses.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Accessed&lt;/em&gt; means: logins from new places, changed recovery details, messages read. &lt;em&gt;Still has access&lt;/em&gt; means: an active session, a linked app token, a forwarding rule, or a cloned session cookie on a device you no longer control.&lt;/p&gt;

&lt;p&gt;Removing the intruder is the easy half. The half people skip is checking every route they left open — which is why "I changed my password and it happened again" is such a common story.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. When it is worth paying an examiner
&lt;/h2&gt;

&lt;p&gt;DIY is enough if you only need your account back. It is not enough if you need to know &lt;strong&gt;who&lt;/strong&gt;, or need evidence that survives scrutiny:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;harassment, stalking, or a partner or ex with physical access to your devices;&lt;/li&gt;
&lt;li&gt;a business account where messages were used to defraud clients;&lt;/li&gt;
&lt;li&gt;a dispute where "I was hacked" is your defence;&lt;/li&gt;
&lt;li&gt;a device you suspect was compromised at the operating-system level, not just the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An examiner works from the device image and the platform records, not from screenshots, and produces something a court can be shown.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we do, and what we won't
&lt;/h2&gt;

&lt;p&gt;We take Instagram and WhatsApp account-compromise cases only with the account owner's written authorization, proof you control the account, and a lawful purpose. We don't break into other people's accounts, and we turn down requests to read a partner's, employee's or ex's messages — that's not a grey area, it's a crime in most jurisdictions.&lt;/p&gt;

&lt;p&gt;If your case fits, the intake is at &lt;a href="https://www.cyberlords.io/hire-a-hacker/instagram/" rel="noopener noreferrer"&gt;cyberlords.io/hire-a-hacker/instagram&lt;/a&gt;, and messaging-app cases are handled at &lt;a href="https://www.cyberlords.io/hire-a-hacker/whatsapp/" rel="noopener noreferrer"&gt;cyberlords.io/hire-a-hacker/whatsapp&lt;/a&gt;. You'll be asked for authorization before anything is touched.&lt;/p&gt;

&lt;p&gt;If it doesn't fit, the six steps above are most of what we'd do in the first hour anyway. Do them, and screenshot everything as you go.&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>infosec</category>
      <category>security</category>
    </item>
    <item>
      <title>Authenticated is not authorized: a practical IDOR test you can run on your own app</title>
      <dc:creator>Cyberlords Security</dc:creator>
      <pubDate>Fri, 30 Oct 2026 17:41:42 +0000</pubDate>
      <link>https://dev.to/cyberlords/authenticated-is-not-authorized-a-practical-idor-test-you-can-run-on-your-own-app-35ke</link>
      <guid>https://dev.to/cyberlords/authenticated-is-not-authorized-a-practical-idor-test-you-can-run-on-your-own-app-35ke</guid>
      <description>&lt;p&gt;Most "we got hacked" stories in web apps don't start with malware. They start with an endpoint that checks &lt;em&gt;who you are&lt;/em&gt; but never checks &lt;em&gt;what you are allowed to touch&lt;/em&gt;. The industry name is broken object-level authorization, or IDOR.&lt;/p&gt;

&lt;p&gt;This is a short, practical guide to testing whether your app has that flaw — the way we do it on an authorized engagement, with written permission, on systems we are paid to test.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why it happens so often
&lt;/h2&gt;

&lt;p&gt;Frameworks make authentication easy: drop in a session, gate the route, done. Authorization is the part with no shortcut, because it depends on your own data model. It's the difference between:&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="c1"&gt;// authenticated, not authorized&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/invoices/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requireLogin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
  &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invoices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and:&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="c1"&gt;// authenticated and authorized&lt;/span&gt;
&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/api/invoices/:id&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;requireLogin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;invoice&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;invoices&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ownerId&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;status&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;end&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;invoice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ten lines of code separate a fine app from a breach notification.&lt;/p&gt;

&lt;h2&gt;
  
  
  The test, in order
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Map every object identifier.&lt;/strong&gt; Query parameters, path segments, JSON body fields, hidden form inputs, GraphQL node IDs, S3 keys, signed-URL tokens. If a value selects a record, it's a target.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Create two accounts you own.&lt;/strong&gt; Account A owns the data, account B tries to reach it. Never test with real user data — that's the difference between a test and an incident.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Replay with B's session.&lt;/strong&gt; Capture A's request in your proxy, drop the session cookie and token, and send it again as B. Look at the status code &lt;em&gt;and&lt;/em&gt; the body: a 200 with &lt;code&gt;{"error":"forbidden"}&lt;/code&gt; is not a fix, and a 403 that still leaks the record name in the message is still a leak.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Try identifier shapes.&lt;/strong&gt; Sequential IDs (&lt;code&gt;1001&lt;/code&gt; to &lt;code&gt;1002&lt;/code&gt;), UUIDs harvested from list endpoints (they are never as secret as people think), slug variations, and &lt;em&gt;nested&lt;/em&gt; resources (&lt;code&gt;/users/7/invoices/99&lt;/code&gt; where the check is on &lt;code&gt;7&lt;/code&gt; only).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Test state changes, not just reads.&lt;/strong&gt; &lt;code&gt;PUT&lt;/code&gt;, &lt;code&gt;PATCH&lt;/code&gt;, &lt;code&gt;DELETE&lt;/code&gt;, role fields, &lt;code&gt;isAdmin&lt;/code&gt;, price, quantity, and the email or phone on an account. Reads leak data; writes destroy it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Check the edges.&lt;/strong&gt; Export endpoints, PDF generators, CSV downloads, share links, webhooks, image proxies, and anything that takes a URL. These are where object checks go missing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The evidence that makes a finding useful
&lt;/h2&gt;

&lt;p&gt;A screenshot of Postman is not a report. Record, for each issue:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the exact request and response pair, with both accounts' identities redacted consistently;&lt;/li&gt;
&lt;li&gt;the impact in business terms ("any authenticated user can read any other tenant's invoices" beats "IDOR on /api/invoices");&lt;/li&gt;
&lt;li&gt;a reproduction path a developer can follow in under five minutes;&lt;/li&gt;
&lt;li&gt;the fix, at the level of the check that was missing, not "add authorization".&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you cannot demonstrate the impact with your own two accounts, you have a hypothesis, not a finding.&lt;/p&gt;

&lt;h2&gt;
  
  
  The legal line, because this matters
&lt;/h2&gt;

&lt;p&gt;Testing someone else's system without permission is a crime in most jurisdictions, whatever the intent. Before a single request goes out you want: written scope (domains, IPs, accounts), the testing window, prohibited techniques, an emergency contact, and a definition of what happens if you find something critical.&lt;/p&gt;

&lt;p&gt;If you are testing your &lt;em&gt;own&lt;/em&gt; product, write the same document anyway. It forces the team to agree on scope, and it is the thing that protects you when a test knocks over production.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you would rather not do it yourself
&lt;/h2&gt;

&lt;p&gt;This is the work we do for a living under signed authorization: scoping, testing, evidence, and a report your developers can act on. You can see how we structure an engagement at &lt;a href="https://www.cyberlords.io/hire-a-hacker/" rel="noopener noreferrer"&gt;cyberlords.io/hire-a-hacker&lt;/a&gt;, and if you only want to read up first there is a longer piece on &lt;a href="https://www.cyberlords.io/blog/hire-hacker-safely-2025" rel="noopener noreferrer"&gt;staying lawful while doing this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;One closing note for developers: the fix is almost never a WAF rule. Centralize the ownership check next to the query, test it in CI with two seeded accounts, and treat a missing check as a failing test rather than a code review comment.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>webdev</category>
      <category>security</category>
      <category>api</category>
    </item>
  </channel>
</rss>
