daemon-sec-cheatsheet

The cheatsheet vault for operators: AD, enumeration, exploitation, priv-esc, web, DFIR
git clone https://git.daemon-sec.xyz/daemon-sec-cheatsheet.git
Log | Files | Refs | README | LICENSE

conflict-and-environment.md (40963B)


      1 ---
      2 title: "Conflict & Environmental Monitoring"
      3 description: "Event datasets, munitions identification, fire and deforestation feeds, and the tools built for documenting harm."
      4 category: osint
      5 subcategory: "Thematic"
      6 tags: [osint, conflict, environment, monitoring, satellite]
      7 tools: [acled, gdelt, firms, sentinel-hub, global-forest-watch, osmp, liveuamap]
      8 difficulty: intermediate
      9 updated: 2026-10-03
     10 references:
     11   - name: "Bellingcat's Online Investigation Toolkit"
     12     url: "https://bellingcat.gitbook.io/toolkit"
     13     author: "Bellingcat"
     14     license: none
     15     relation: derived
     16     note: "Tool catalogue: names, descriptions, cost flags and links for this area."
     17   - name: "OSINT Newsletter Tools Library"
     18     url: "https://tools.osintnewsletter.com"
     19     author: "The OSINT Newsletter"
     20     license: none
     21     relation: derived
     22     note: "Second tool catalogue, cross-checked against the above."
     23 ---
     24 
     25 ## What this covers
     26 
     27 Two thematic areas with mature, purpose-built open datasets: armed conflict and environmental
     28 change. Both are unusual in OSINT for having authoritative structured data behind them rather than
     29 just tools, which moves the skill from finding sources to reading methodologies and querying them
     30 properly.
     31 
     32 ## Method
     33 
     34 1. **Start from a bounded question with a place and a date range.** These are datasets, not search
     35    engines — a query without a bounding box and a window either returns nothing useful or exceeds
     36    your quota.
     37 2. **Read the codebook before the data.** What ACLED counts as an event, how FIRMS defines a
     38    thermal anomaly, what a Global Forest Watch alert confidence class means: each materially
     39    changes what a number means, and each is documented.
     40 3. **Query the dataset rather than the dashboard.** Dashboards aggregate in ways you cannot audit
     41    and cannot cite. Pull the records, store them with the retrieval date, and do your own
     42    aggregation.
     43 4. **Establish the baseline before the anomaly.** One fire detection at an industrial site means
     44    nothing until you know how often that pixel normally burns. Pull the same query for the previous
     45    year and the previous month.
     46 5. **Corroborate across two independent feeds.** Independence means different sensors or different
     47    collection methods — a VIIRS hotspot and a Sentinel-2 burn scar, an ACLED event and a dated
     48    photograph, a GDELT article cluster and a satellite image. Two aggregators that both scrape the
     49    same wire service are one source.
     50 6. **For munitions, work from markings outward**, and write "consistent with" unless you have
     51    stencilling, lot numbers or a fuze you can read. This is the single most common place
     52    open-source conflict reporting goes wrong.
     53 7. **Record the evidentiary chain for each claim**: the dataset and its version, the exact query,
     54    the retrieval timestamp, the hash of any imagery you downloaded, and the second source. A
     55    finding that cannot be re-run is not a finding.
     56 
     57 ## Conflict
     58 
     59 | Source | What it gives you |
     60 | --- | --- |
     61 | [ACLED](https://acleddata.com/) | Coded conflict events — date, location, actors, event type, fatalities — globally, with a published methodology and an API. The reference dataset. |
     62 | [GDELT](https://www.gdeltproject.org/) | Global news coverage indexed by location, theme, tone and actor, updated every 15 minutes. Not events; coverage of events. |
     63 | [Liveuamap](https://liveuamap.com/) | Near-real-time mapped events aggregated from social media. Fast but unverified; a lead generator only. |
     64 | [Geoconfirmed](https://geoconfirmed.org/) | Volunteer-geolocated conflict media, each entry with the coordinates and the reasoning. Verified work you can audit. |
     65 | [Open Source Munitions Portal](https://osmp.ngo/) | Identification reference for munitions and their remnants, which is how you turn a photo of debris into a weapon type. |
     66 | [Bellingcat's Civilian Harm datasets](https://ukraine.bellingcat.com/) | Verified incident databases with the sourcing attached to each entry. |
     67 
     68 ### ACLED API
     69 
     70 Coded event data with a documented methodology, which is what separates it from every aggregator in
     71 the table above. Each record carries a date, coordinates with a stated precision level, named
     72 actors, an event type and sub-event type, a fatality estimate, and the sources it was coded from.
     73 
     74 **The API moved and the auth model changed.** The old `api.acleddata.com` host with
     75 `key=`/`email=` query parameters is gone — the hostname no longer resolves, and the key system was
     76 retired in September 2025. Current access is a bearer token from an OAuth password grant against
     77 your myACLED account, used against `acleddata.com/api/`.
     78 
     79 ```bash
     80 # token: valid 24 hours, with a refresh token valid 14 days
     81 TOKEN=$(curl -s -X POST 'https://acleddata.com/oauth/token' \
     82   -d 'username=you@example.com' --data-urlencode 'password=YOUR_PASSWORD' \
     83   -d 'grant_type=password' -d 'client_id=acled' -d 'scope=authenticated' \
     84   | jq -r .access_token)
     85 ```
     86 
     87 ```bash
     88 # events in one country over a window, as JSON
     89 curl -s -H "Authorization: Bearer $TOKEN" -G 'https://acleddata.com/api/acled/read' \
     90   --data-urlencode 'country=Ukraine' \
     91   --data-urlencode 'event_date=2026-01-01|2026-03-31' \
     92   --data-urlencode 'event_date_where=BETWEEN' --data-urlencode 'limit=0' \
     93   | jq '.count'
     94 
     95 # CSV straight to disk, which is what you archive
     96 curl -s -H "Authorization: Bearer $TOKEN" -G 'https://acleddata.com/api/acled/read' \
     97   --data-urlencode '_format=csv' --data-urlencode 'country=Sudan' \
     98   --data-urlencode 'event_date=2026-01-01|2026-03-31' \
     99   --data-urlencode 'event_date_where=BETWEEN' --data-urlencode 'limit=0' \
    100   -o "acled-sudan-$(date -u +%F).csv"
    101 
    102 # one event type only — the sub-event taxonomy is where the precision is
    103 curl -s -H "Authorization: Bearer $TOKEN" -G 'https://acleddata.com/api/acled/read' \
    104   --data-urlencode 'country=Nigeria' \
    105   --data-urlencode 'event_type=Explosions/Remote violence' \
    106   --data-urlencode 'event_date=2026-01-01|2026-03-31' \
    107   --data-urlencode 'event_date_where=BETWEEN' | jq '.data | length'
    108 
    109 # a named actor's events, for an order-of-battle or attribution question
    110 curl -s -H "Authorization: Bearer $TOKEN" -G 'https://acleddata.com/api/acled/read' \
    111   --data-urlencode 'actor1=Military Forces of Sudan (2019-)' \
    112   --data-urlencode 'actor1_where=%3D' --data-urlencode 'limit=200' | jq '.count'
    113 
    114 # narrow to an admin region, which is how you bound to a locality
    115 curl -s -H "Authorization: Bearer $TOKEN" -G 'https://acleddata.com/api/acled/read' \
    116   --data-urlencode 'country=Mali' --data-urlencode 'admin1=Mopti' \
    117   --data-urlencode 'event_date=2026-01-01|2026-03-31' \
    118   --data-urlencode 'event_date_where=BETWEEN' | jq '.data | length'
    119 
    120 # only the fields you need, which keeps responses small
    121 curl -s -H "Authorization: Bearer $TOKEN" -G 'https://acleddata.com/api/acled/read' \
    122   --data-urlencode 'country=Ukraine' --data-urlencode 'limit=50' \
    123   --data-urlencode 'fields=event_date|event_type|sub_event_type|location|latitude|longitude|fatalities|source' \
    124   | jq '.data[0]'
    125 
    126 # the deleted-records endpoint, so a stored copy can be reconciled with upstream revisions
    127 curl -s -H "Authorization: Bearer $TOKEN" -G 'https://acleddata.com/api/deleted/read' \
    128   --data-urlencode 'deleted_timestamp=1735689600' | jq '.count'
    129 ```
    130 
    131 The `R` package `acledR` and the `acled` Python package both wrap this and handle the token
    132 refresh; either is less work than scripting the grant yourself if you query regularly. Access is
    133 free for non-commercial use with registration, and the terms restrict redistribution of the raw
    134 data — cite and link rather than re-publishing the CSV.
    135 
    136 Read the codebook before drawing any conclusion. Three things in particular: coordinate precision
    137 is a graded field, and a precision-3 event is located to an admin region rather than a point;
    138 fatality figures are the most conservative reported estimate, not a count; and event density tracks
    139 reporting density, so comparing two regions compares their journalism as much as their violence.
    140 The `deleted` endpoint exists because ACLED revises history as better sourcing arrives, which means
    141 a stored extract drifts from upstream.
    142 
    143 ### GDELT DOC 2.0 API
    144 
    145 Global news coverage, indexed every 15 minutes across languages, queryable by phrase, location,
    146 theme, tone and source country. It tells you what was *reported*, where and in what volume, which
    147 is a different and complementary question to what happened. No key, no registration.
    148 
    149 ```bash
    150 # articles matching a phrase, geographically filtered, as JSON
    151 curl -s -G 'https://api.gdeltproject.org/api/v2/doc/doc' \
    152   --data-urlencode 'query="artillery" sourcecountry:UP' \
    153   --data-urlencode 'mode=artlist' --data-urlencode 'format=json' \
    154   --data-urlencode 'maxrecords=100' --data-urlencode 'timespan=7d' \
    155   | jq '.articles[] | {seendate, domain, title, language}'
    156 
    157 # coverage volume over time — the shape of the curve is the finding
    158 curl -s -G 'https://api.gdeltproject.org/api/v2/doc/doc' \
    159   --data-urlencode 'query="port of berbera"' \
    160   --data-urlencode 'mode=timelinevol' --data-urlencode 'format=json' \
    161   --data-urlencode 'timespan=3m' | jq '.timeline[0].data[-10:]'
    162 
    163 # an exact window rather than a rolling span
    164 curl -s -G 'https://api.gdeltproject.org/api/v2/doc/doc' \
    165   --data-urlencode 'query="chemical plant" sourcelang:eng' \
    166   --data-urlencode 'mode=artlist' --data-urlencode 'format=json' \
    167   --data-urlencode 'startdatetime=20260301000000' \
    168   --data-urlencode 'enddatetime=20260315000000' | jq '.articles | length'
    169 
    170 # which countries are covering a story, and which are not
    171 curl -s -G 'https://api.gdeltproject.org/api/v2/doc/doc' \
    172   --data-urlencode 'query="grain corridor"' \
    173   --data-urlencode 'mode=timelinesourcecountry' --data-urlencode 'format=json' \
    174   --data-urlencode 'timespan=1m' | jq '[.timeline[].series] | .[0:8]'
    175 
    176 # tone distribution, for spotting a coordinated framing shift
    177 curl -s -G 'https://api.gdeltproject.org/api/v2/doc/doc' \
    178   --data-urlencode 'query="sanctions relief"' \
    179   --data-urlencode 'mode=tonechart' --data-urlencode 'format=json' \
    180   --data-urlencode 'timespan=2w' | jq '.tonechart'
    181 
    182 # images published alongside the coverage, which sometimes surface the source photo
    183 curl -s -G 'https://api.gdeltproject.org/api/v2/doc/doc' \
    184   --data-urlencode 'query="refinery fire"' \
    185   --data-urlencode 'mode=imagecollageinfo' --data-urlencode 'format=json' \
    186   --data-urlencode 'timespan=3d' | jq '.images[0:5]'
    187 ```
    188 
    189 The DOC API serves a rolling window — roughly the last three months by default, reaching back to
    190 1 January 2017 with explicit datetimes — and caps at 250 records per request for article and image
    191 modes. For anything longer or larger, the GDELT Event and GKG tables are published on BigQuery and
    192 as raw CSV, which is the right route for a multi-year series.
    193 
    194 What it does not tell you: GDELT indexes articles, not events, so one incident covered by four
    195 hundred outlets is four hundred records. A volume spike measures attention. Syndication means the
    196 same wire copy appears under many domains, which is why a GDELT cluster and an aggregator that
    197 scrapes the same wires are not two independent sources.
    198 
    199 ### NASA FIRMS
    200 
    201 Active fire and thermal anomaly detections from MODIS and VIIRS, available within three hours of
    202 satellite overpass. Thermal detection is a far broader OSINT primitive than wildfire monitoring:
    203 gas flaring, industrial process heat, shelling, burning buildings and crop residue all register.
    204 
    205 Get a free `MAP_KEY` from
    206 [firms.modaps.eosdis.nasa.gov/api/map_key](https://firms.modaps.eosdis.nasa.gov/api/map_key/).
    207 
    208 ```bash
    209 export MAP_KEY='your-map-key'
    210 ```
    211 
    212 ```bash
    213 # check the key works and how much of your quota is left
    214 curl -s "https://firms.modaps.eosdis.nasa.gov/mapserver/mapkey_status/?MAP_KEY=$MAP_KEY"
    215 
    216 # detections in a bounding box over the last day — order is west,south,east,north
    217 curl -s "https://firms.modaps.eosdis.nasa.gov/api/area/csv/$MAP_KEY/VIIRS_SNPP_NRT/30.0,46.0,36.0,50.0/1"
    218 
    219 # a specific past date, with the day range starting from it (1-10 days)
    220 curl -s "https://firms.modaps.eosdis.nasa.gov/api/area/csv/$MAP_KEY/VIIRS_NOAA20_NRT/30.0,46.0,36.0,50.0/2/2026-03-11" \
    221   -o firms-2026-03-11.csv
    222 
    223 # the archival standard-quality product, for anything older than the NRT window
    224 curl -s "https://firms.modaps.eosdis.nasa.gov/api/area/csv/$MAP_KEY/VIIRS_SNPP_SP/30.0,46.0,36.0,50.0/5/2025-07-01" \
    225   -o firms-archive.csv
    226 
    227 # which products cover which dates, so you query one that exists
    228 curl -s "https://firms.modaps.eosdis.nasa.gov/api/data_availability/csv/$MAP_KEY/all"
    229 
    230 # filter to high-confidence daytime detections at a site
    231 curl -s "https://firms.modaps.eosdis.nasa.gov/api/area/csv/$MAP_KEY/VIIRS_SNPP_NRT/30.0,46.0,36.0,50.0/1" \
    232   | awk -F, 'NR==1 || ($10=="h" || $10>=80)'
    233 
    234 # a year of the same small box, to build the baseline before you call an anomaly
    235 for d in 2025-0{1..9}-01 2025-1{0..2}-01; do
    236   curl -s "https://firms.modaps.eosdis.nasa.gov/api/area/csv/$MAP_KEY/VIIRS_SNPP_SP/30.0,46.0,36.0,50.0/10/$d"
    237   sleep 2
    238 done > baseline.csv
    239 ```
    240 
    241 The quota is 5,000 transactions per 10-minute window per key, and a large bounding box counts as
    242 several, so loop with a sleep. Day range per request is 1–10. VIIRS at 375 m resolves far more than
    243 MODIS at 1 km and is what you want for anything at a single site; the `_NRT` products are the fast
    244 ones, `_SP` the reprocessed archive.
    245 
    246 Reading a detection: `confidence` is `l`/`n`/`h` for VIIRS and a 0–100 percentage for MODIS, `frp`
    247 is fire radiative power in megawatts, `daynight` matters because daytime detections suffer more
    248 false positives from reflective surfaces, and `scan`/`track` give the actual pixel footprint — the
    249 detection is a pixel, not a point, so the coordinates are the pixel centre and the real event is
    250 somewhere within a few hundred metres of it.
    251 
    252 A hotspot is a thermal anomaly and nothing more. Gas flares burn continuously and appear every
    253 single night, which is why the baseline query above matters: the finding is not "a hotspot at this
    254 site", it is "a hotspot at a site that produced none in the preceding twelve months".
    255 
    256 ### Sentinel Hub on the Copernicus Data Space Ecosystem
    257 
    258 Free Sentinel-1, Sentinel-2 and Sentinel-3 imagery, both as an interactive browser and as an API.
    259 Use the browser to find the scene and settle the band combination; use the API to pull the exact
    260 same thing reproducibly, with a date and a bounding box you can cite.
    261 
    262 **Access moved to the Copernicus Data Space Ecosystem**, which replaced both the old Copernicus
    263 Open Access Hub and the commercial Sentinel Hub free tier for Sentinel data. Register at
    264 [dataspace.copernicus.eu](https://dataspace.copernicus.eu/), create an OAuth client in your account
    265 settings, and you get a monthly processing-unit quota at no cost.
    266 
    267 Start in [EO Browser](https://browser.dataspace.copernicus.eu/): set the area, set the date range,
    268 pick Sentinel-2 L2A, and step through the available passes. The band combinations that make change
    269 visible where true colour hides it:
    270 
    271 ```text
    272 Burn scars (Sentinel-2):        B12, B8A, B4   — recent burns go red-brown, vegetation green
    273 Vegetation health (NDVI):       (B8 - B4) / (B8 + B4)
    274 Normalised burn ratio (NBR):    (B8 - B12) / (B8 + B12), differenced pre/post for severity
    275 Water and flooding:             B8A, B11, B4   — water goes near-black, wet soil distinct
    276 Bare soil / earthworks:         B11, B8, B2    — fresh excavation and berms separate from vegetation
    277 Smoke and plumes:               true colour, then B12/B8A/B4 to see through thin smoke
    278 Sentinel-1 radar (SAR):         VV/VH, for cloud cover, night, and detecting hulls at sea
    279 ```
    280 
    281 Then reproduce it through the API:
    282 
    283 ```bash
    284 # token, valid about ten minutes
    285 TOKEN=$(curl -s -X POST \
    286   'https://identity.dataspace.copernicus.eu/auth/realms/CDSE/protocol/openid-connect/token' \
    287   -H 'content-type: application/x-www-form-urlencoded' \
    288   -d 'grant_type=client_credentials' -d 'client_id=YOUR_CLIENT_ID' \
    289   --data-urlencode 'client_secret=YOUR_CLIENT_SECRET' | jq -r .access_token)
    290 
    291 # which Sentinel-2 passes exist over this box in this window, and how cloudy
    292 curl -s -X POST 'https://sh.dataspace.copernicus.eu/api/v1/catalog/1.0.0/search' \
    293   -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
    294   -d '{"collections":["sentinel-2-l2a"],
    295        "bbox":[30.0,46.0,30.3,46.3],
    296        "datetime":"2026-03-01T00:00:00Z/2026-03-20T00:00:00Z",
    297        "limit":20,
    298        "fields":{"include":["id","properties.datetime","properties.eo:cloud_cover"]}}' \
    299   | jq '.features[] | {id, datetime:.properties.datetime, cloud:.properties["eo:cloud_cover"]}'
    300 
    301 # render a false-colour burn-scar image for one date, as a GeoTIFF you can hash
    302 curl -s -X POST 'https://sh.dataspace.copernicus.eu/api/v1/process' \
    303   -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
    304   -d '{"input":{"bounds":{"bbox":[30.0,46.0,30.3,46.3]},
    305         "data":[{"type":"sentinel-2-l2a",
    306                  "dataFilter":{"timeRange":{"from":"2026-03-11T00:00:00Z","to":"2026-03-12T00:00:00Z"}}}]},
    307        "output":{"width":1024,"height":1024,"responses":[{"identifier":"default","format":{"type":"image/tiff"}}]},
    308        "evalscript":"//VERSION=3\nfunction setup(){return {input:[\"B12\",\"B8A\",\"B04\"],output:{bands:3}}}\nfunction evaluatePixel(s){return [s.B12*2.5, s.B8A*2.5, s.B04*2.5]}"}' \
    309   -o burnscar-2026-03-11.tiff
    310 ```
    311 
    312 Hash the GeoTIFF the moment you download it and record the scene ID, the exact bounding box and the
    313 acquisition datetime. That tuple is what makes the imagery claim reproducible — "a Sentinel-2 image
    314 from around then" is not a citation.
    315 
    316 Quotas are monthly processing units and are replenished on the first of the month; a 1024-pixel
    317 request is cheap, a full-resolution multi-band pull over a province is not. Sentinel-2 revisits
    318 every five days at the equator and the optical bands see nothing through cloud, which is why
    319 Sentinel-1 radar is the fallback for a specific date you cannot miss.
    320 
    321 ### Global Forest Watch Data API
    322 
    323 Deforestation and fire alerts as a queryable dataset rather than a dashboard. The integrated alerts
    324 layer combines three independent alert systems (GLAD-L, GLAD-S2 and RADD radar), which makes it one
    325 of the few places where cross-sensor corroboration is already built in and labelled.
    326 
    327 Create an account, exchange it for a token, then mint an API key; the key goes in an `x-api-key`
    328 header. Without one, every query returns a 401 telling you so.
    329 
    330 ```bash
    331 # sign up and get a short-lived token
    332 curl -s -X POST 'https://data-api.globalforestwatch.org/auth/token' \
    333   -d 'username=you@example.com' --data-urlencode 'password=YOUR_PASSWORD' | jq -r .data.access_token
    334 
    335 # mint an API key with that token
    336 curl -s -X POST 'https://data-api.globalforestwatch.org/auth/apikey' \
    337   -H "Authorization: Bearer $GFW_TOKEN" -H 'Content-Type: application/json' \
    338   -d '{"alias":"osint-research","organization":"research","email":"you@example.com","domains":[]}' \
    339   | jq -r .data.api_key
    340 ```
    341 
    342 ```bash
    343 export GFW_KEY='your-api-key'
    344 
    345 # what datasets exist, and what each version is called
    346 curl -s 'https://data-api.globalforestwatch.org/datasets' \
    347   | jq -r '.data[].dataset' | grep -E 'integrated_alerts|viirs|burned'
    348 
    349 # daily integrated deforestation alerts for one country
    350 curl -s -H "x-api-key: $GFW_KEY" -G \
    351   'https://data-api.globalforestwatch.org/dataset/gadm__integrated_alerts__iso_daily_alerts/latest/query/json' \
    352   --data-urlencode "sql=SELECT iso, gfw_integrated_alerts__date, SUM(alert__count) AS alerts
    353                     FROM results WHERE iso='BRA' AND gfw_integrated_alerts__date >= '2026-02-01'
    354                     GROUP BY iso, gfw_integrated_alerts__date ORDER BY 2 DESC" | jq '.data[0:5]'
    355 
    356 # down to a second-level administrative area, which is a usable locality
    357 curl -s -H "x-api-key: $GFW_KEY" -G \
    358   'https://data-api.globalforestwatch.org/dataset/gadm__integrated_alerts__adm2_daily_alerts/latest/query/json' \
    359   --data-urlencode "sql=SELECT adm1, adm2, SUM(alert__count) AS alerts FROM results
    360                     WHERE iso='COL' AND gfw_integrated_alerts__date >= '2026-01-01'
    361                     GROUP BY adm1, adm2 ORDER BY alerts DESC LIMIT 20" | jq '.data[0:5]'
    362 
    363 # alert confidence, which is where the cross-sensor corroboration lives
    364 curl -s -H "x-api-key: $GFW_KEY" -G \
    365   'https://data-api.globalforestwatch.org/dataset/gadm__integrated_alerts__adm2_daily_alerts/latest/query/json' \
    366   --data-urlencode "sql=SELECT gfw_integrated_alerts__confidence, SUM(alert__count) FROM results
    367                     WHERE iso='PER' GROUP BY 1" | jq '.data'
    368 
    369 # VIIRS fire alerts from the same API, so fire and forest loss share one query layer
    370 curl -s -H "x-api-key: $GFW_KEY" -G \
    371   'https://data-api.globalforestwatch.org/dataset/gadm__viirs__adm2_daily_alerts/latest/query/json' \
    372   --data-urlencode "sql=SELECT adm1, adm2, SUM(alert__count) FROM results
    373                     WHERE iso='IDN' AND alert__date >= '2026-02-01' GROUP BY 1,2 ORDER BY 3 DESC LIMIT 10" \
    374   | jq '.data[0:5]'
    375 
    376 # which fields a dataset actually has, before you guess a column name
    377 curl -s -H "x-api-key: $GFW_KEY" \
    378   'https://data-api.globalforestwatch.org/dataset/gadm__integrated_alerts__adm2_daily_alerts/latest/fields' \
    379   | jq -r '.data[].name'
    380 
    381 # CSV instead of JSON, for a spreadsheet handover
    382 curl -s -H "x-api-key: $GFW_KEY" -G \
    383   'https://data-api.globalforestwatch.org/dataset/gadm__integrated_alerts__iso_daily_alerts/latest/query/csv' \
    384   --data-urlencode "sql=SELECT * FROM results WHERE iso='BRA' LIMIT 1000" -o gfw-bra.csv
    385 ```
    386 
    387 Versions are dated (`v20261003`), and `latest` resolves to the newest — pin the explicit version in
    388 anything you cite, because `latest` moves under you. A `highest` confidence integrated alert means
    389 more than one of the three systems detected the same loss, which is the built-in second source; a
    390 `low` confidence alert is a single-sensor detection and should be treated as a lead.
    391 
    392 An alert is tree-cover loss, not a crime. Legal logging concessions, plantation harvest cycles,
    393 storm damage and seasonal leaf-off all generate alerts. The question that turns an alert into a
    394 story is whether the polygon falls inside a protected area or a concession boundary, and that is a
    395 separate dataset join.
    396 
    397 ### Open Source Munitions Portal
    398 
    399 A searchable reference library of verified photographs of munitions and their remnants, built by
    400 Airwars and Armament Research Services. Web-only, no API, and the correct first stop when you have
    401 a photograph of debris and no identification. Over a thousand verified entries, weighted heavily
    402 towards the Middle East and Ukraine.
    403 
    404 Search at [osmp.ngo](https://osmp.ngo/) by munition category, country, date or free text, then work
    405 the comparison deliberately:
    406 
    407 ```text
    408 1. Measure first         find a scale reference in your photo — a hand, a boot, a kerb, a
    409                          standard brick — and estimate diameter and length before you
    410                          browse, so you are filtering rather than pattern-matching
    411 2. Filter by category     bomb, rocket, artillery projectile, guided missile, submunition.
    412                          Getting the category right eliminates most of the library
    413 3. Compare the parts     tail assembly and fin count, fuze well, lug spacing, nose profile,
    414                          body seams, driving band. These are discriminating; overall shape
    415                          is not
    416 4. Read the stencilling  alphanumeric markings, lot numbers, factory codes, colour bands.
    417                          A legible lot number is the only thing that gets you to a
    418                          production batch and a country of manufacture
    419 5. Check the remnant      fragmentation pattern and wall thickness distinguish families
    420                          that look identical intact
    421 6. Cross-reference        CAT-UXO for explosive ordnance detail and Bulletpicker's
    422                          manual archive for the original technical drawings
    423 ```
    424 
    425 Record the OSMP entry ID for every comparison you made, including the ones you rejected, and the
    426 specific features you matched on. "Consistent with a 9M27K rocket on the basis of fin count and
    427 motor diameter, per OSMP entry NNNN" is defensible. "A cluster munition" is not, unless you can
    428 read the markings.
    429 
    430 The geographic bias is a real limitation: a munition used outside the Middle East or Ukraine may
    431 simply be absent from the library, and absence is not evidence of a different weapon. Pair OSMP
    432 with [CAT-UXO](https://cat-uxo.com/) and
    433 [Bulletpicker](https://bulletpicker.com/)'s scanned ordnance manuals, which have broader scope and
    434 worse search.
    435 
    436 ## Corroborating one event across two independent feeds
    437 
    438 The single most useful habit in this area, and the thing that makes a claim stand up. "Independent"
    439 means a different sensor or a different collection route, not a different website.
    440 
    441 ```text
    442 Claim      a munitions strike on a named facility, 11 March 2026, from a social post
    443 Source A   ACLED event: query country + admin1 + date, with event_type
    444            Explosions/Remote violence. Returns a coded event, its own sources, a
    445            coordinate precision level and a fatality estimate
    446 Source B   NASA FIRMS: VIIRS detections in a tight box around the facility for that
    447            date and the day after. A thermal anomaly at the right pixel is an
    448            independent sensor observation, not a report
    449 Source C   Sentinel-2 via CDSE: the first clear pass after the date, false-colour
    450            B12/B8A/B4. A new burn scar or structural change on imagery acquired after
    451            and absent before is the third, strongest leg
    452 Baseline   the same FIRMS box for the preceding year, to show the pixel does not
    453            routinely register; the preceding Sentinel-2 pass, to show the scar is new
    454 Negative   GDELT timelinevol for the facility name, to see whether coverage preceded
    455            the imagery — coverage before the satellite pass means the reporting is not
    456            derived from the imagery and is genuinely separate
    457 Record     per leg: dataset and pinned version, exact query, retrieval timestamp,
    458            SHA-256 of any downloaded raster, and the scene ID with its acquisition time
    459 ```
    460 
    461 Two legs from the same family is one leg: ACLED and Liveuamap both code from media reporting,
    462 GDELT and a news aggregator both index the same wires, MODIS and VIIRS are different sensors but
    463 can be on the same platform pass. A sensor observation plus a reported event is a genuine pair, and
    464 imagery plus a sensor observation is better.
    465 
    466 State the negative result as explicitly as the positive one. "No VIIRS detection in a 2 km box on
    467 either date, and the first clear Sentinel-2 pass is nine days later" is a useful finding about the
    468 limits of what can be established, and publishing it is what distinguishes this work from
    469 advocacy.
    470 
    471 ## Environment
    472 
    473 | Source | What it gives you |
    474 | --- | --- |
    475 | [Global Forest Watch](https://www.globalforestwatch.org/) | Deforestation alerts and tree-cover change, near-real-time, with an API behind it. |
    476 | [NASA FIRMS](https://firms.modaps.eosdis.nasa.gov/) | Active fire and thermal anomaly detections, updated within three hours of overpass. |
    477 | [Global Fishing Watch](https://globalfishingwatch.org/map) | Apparent fishing effort and vessel-behaviour events inferred from AIS. See [transport tracking](/sheets/osint/transport-tracking) for its API. |
    478 | [Copernicus Browser](https://browser.dataspace.copernicus.eu/) | Free Sentinel-1/2/3 imagery with band combinations for burn scars, water, vegetation and earthworks. |
    479 | [UNOSAT](https://unosat.org/products) | UN satellite analyses of humanitarian emergencies, already interpreted and published with methodology. |
    480 | [Resource Watch](https://resourcewatch.org/) | 300+ environmental and human-wellbeing datasets, several of them real-time. |
    481 
    482 ## Tool reference
    483 
    484 | Tool | What it does | Cost |
    485 | --- | --- | --- |
    486 | [ACLED (Armed Conflict Location & Event Data Project)](https://acleddata.com/) | ACLED provides data and analysis on political violence and protest around the world, facilitating research, policy making, and journalistic reporting. | partly free |
    487 | [AllTrails](https://www.alltrails.com/) | AllTrails.com is a tool for discovering hiking, biking, and running trails worldwide, providing detailed trail maps, user reviews, and navigation support… | partly free |
    488 | [Amazonia Socio Ambiental (RAISG)](https://www.amazoniasocioambiental.org/en/) | Amazon rainforest maps and shapefiles of natural protected areas, concessions, indigenous territories, oil, mining, roads, fires, deforestation in… | free |
    489 | [Aqueduct Water Risk Atlas](https://www.wri.org/applications/aqueduct/water-risk-atlas/) | The Aqueduct water Risk Atlas, developed by the World Resources Institute (WRI), is an interactive platform for assessing water-related risks globally. | free |
    490 | [BirdNet](https://birdnet.cornell.edu/map) | Identify bird sounds - find bird sounds on a global map. | free |
    491 | [Bulletpicker](https://bulletpicker.com/pdf/bulletpicker-24-11-20.zip) | Bulletpicker.com is a collection of ammunition guidebooks and manuals from several different armed forces. | free |
    492 | [CITES Trade Database](https://trade.cites.org/) | Around 23 million records of trade in wildlife since 1975. | free |
    493 | [CryO Tools](https://cryo-tools.org/) | Scientific tools for investigating the cryosphere (areas with snow & ice) | free |
    494 | [EIA Global Environmental Crime Tracker](https://eia-international.org/global-environmental-crime-tracker/) | Map/tracker of environmental crimes including trade in ivory, rhino, big cats, and other exotic animals. | free |
    495 | [Environmental Justice Atlas](https://ejatlas.org/) | Map of environmental-related conflict globally | free |
    496 | [Global Monitoring System - ECOSOLVE](https://www.ecosolve.eco/dashboard) | Illicit online wildlife markets data from over 30 countries and regions | free |
    497 | [Google Flood Hub](https://sites.research.google/floods/) | A visual tool to monitor river levels and forecast floods based on AI models developed by Google Research. | free |
    498 | [Locust Hub](https://locust-hub-hqfao.hub.arcgis.com/) | A repository for desert locust data with maps and other resources for tracking movements, early detection and planning locust control interventions. | free |
    499 | [Merlin](https://merlin.allaboutbirds.org/) | Identify birds (visually), through an app. | free |
    500 | [Movebank](https://www.movebank.org/) | Platform for animal tracking data. | free |
    501 | [Nullschool Earth Map](https://earth.nullschool.net/#current) | View current and historic wind, weather, ocean and pollution conditions on an interactive animated map. | partly free |
    502 | [Police Records Access Project](https://clean.calmatters.org/) | A database providing searchable access to California law enforcement records including police use-of-force incidents, shootings, and misconduct cases. | free |
    503 | [Resource Watch](https://resourcewatch.org/) | A free open-data platform that hosts 300+ datasets on different topics relating to the environment and human well-being, including real-time datasets. | free |
    504 | [River Runner Global](https://river-runner-global.samlearner.com/) | Calculate which water stream a drop of rain will follow | free |
    505 | [Species+](https://www.speciesplus.net/species) | Centralized website with vulnerable species information. | free |
    506 | [UNOSAT Analyses](https://unosat.org/products) | UNOSAT Analyses is a tool that maps humanitarian emergencies across the globe utilising United Nations Satellite Centre data. | free |
    507 | [WildEye](https://global.wildeye.oxpeckers.org/) | Tracking tool for data on environmental and wildlife crime cases, including court cases and convictions, across the globe. | free |
    508 | [Wildlife Trade Portal](https://www.wildlifetradeportal.org/) | An open-source tool to search wildlife seizure data worldwide. | free |
    509 | [WildMe & WildBook](https://wildme.org/#/platforms/bass) | Open source pattern recognition software to identify unique whales, sharks, zebras, jaguars, skunks, fish and much more. | free |
    510 | [World Database on Protected and Conserved Areas](https://www.protectedplanet.net/en/search-areas?geo_type=site) | A comprehensive global database on terrestrial and marine protected areas. Also known as Protected Planet. | free |
    511 | CAT UXO | A repository for professionals working in the explosive ordnance disposal (EOD) space. | partly free |
    512 
    513 ## Pitfalls
    514 
    515 - **Event datasets reflect reporting, not reality.** Areas with more journalists produce more
    516   recorded events. Never read event counts as a direct measure of violence.
    517 - **Real-time aggregators are unverified.** Liveuamap and similar repost claims. Verify before use.
    518 - **Thermal detections have mundane causes.** Flaring, agricultural burning and industrial process
    519   heat all look alike from orbit.
    520 - **Deforestation alerts include legal logging** and seasonal change. Alert ≠ crime.
    521 - **Documenting harm carries duty of care.** Graphic material needs handling policies, and
    522   identifying victims or witnesses can endanger them. Minimise what you publish.
    523 
    524 ## Worked example
    525 
    526 One datum: a coordinate and a date. `46.482, 30.724` on 11 March 2026, from a post claiming a
    527 strike on a grain terminal. The coordinate is real and the returns below are illustrative; what
    528 matters is which query answers which part of the claim.
    529 
    530 ```bash
    531 # 1. was anything coded as an event there
    532 TOKEN=$(curl -s -X POST 'https://acleddata.com/oauth/token' \
    533   -d 'username=you@example.com' --data-urlencode 'password=PW' \
    534   -d 'grant_type=password' -d 'client_id=acled' -d 'scope=authenticated' | jq -r .access_token)
    535 
    536 curl -s -H "Authorization: Bearer $TOKEN" -G 'https://acleddata.com/api/acled/read' \
    537   --data-urlencode 'country=Ukraine' --data-urlencode 'admin1=Odesa' \
    538   --data-urlencode 'event_date=2026-03-10|2026-03-13' \
    539   --data-urlencode 'event_date_where=BETWEEN' \
    540   --data-urlencode 'fields=event_date|sub_event_type|location|latitude|longitude|geo_precision|fatalities|source' \
    541   | jq '.data[]'
    542 # one event, 2026-03-11, sub_event_type "Shelling/artillery/missile attack",
    543 # geo_precision 2, coordinates the city centroid rather than the terminal
    544 ```
    545 
    546 Geo-precision 2 means ACLED located this to a town, not a point — so it corroborates that something
    547 happened in Odesa that day, and says nothing about this coordinate.
    548 
    549 ```bash
    550 # 2. an independent sensor: thermal detections in a tight box around the terminal
    551 curl -s "https://firms.modaps.eosdis.nasa.gov/api/area/csv/$MAP_KEY/VIIRS_SNPP_NRT/30.70,46.46,30.75,46.50/2/2026-03-11"
    552 # two detections, 2026-03-11 ~22:40 UTC, frp 4.8 and 2.1, confidence n, daynight N
    553 ```
    554 
    555 A night-time detection with that radiative power inside a 4 km box is a real heat source, and
    556 nothing about it came from a news report.
    557 
    558 ```bash
    559 # 3. the baseline — does this pixel burn routinely
    560 for d in 2025-03-01 2025-06-01 2025-09-01 2025-12-01 2026-01-01 2026-02-01; do
    561   curl -s "https://firms.modaps.eosdis.nasa.gov/api/area/csv/$MAP_KEY/VIIRS_SNPP_SP/30.70,46.46,30.75,46.50/10/$d" | tail -n +2
    562   sleep 2
    563 done | wc -l
    564 # 0 — no detections in that box across sixty sampled days of the preceding year
    565 ```
    566 
    567 That is what converts the hotspot from an observation into an anomaly.
    568 
    569 ```bash
    570 # 4. imagery: find the first clear pass after the date
    571 TOK=$(curl -s -X POST \
    572   'https://identity.dataspace.copernicus.eu/auth/realms/CDSE/protocol/openid-connect/token' \
    573   -H 'content-type: application/x-www-form-urlencoded' \
    574   -d 'grant_type=client_credentials' -d 'client_id=ID' \
    575   --data-urlencode 'client_secret=SECRET' | jq -r .access_token)
    576 
    577 curl -s -X POST 'https://sh.dataspace.copernicus.eu/api/v1/catalog/1.0.0/search' \
    578   -H "Authorization: Bearer $TOK" -H 'Content-Type: application/json' \
    579   -d '{"collections":["sentinel-2-l2a"],"bbox":[30.70,46.46,30.75,46.50],
    580        "datetime":"2026-03-08T00:00:00Z/2026-03-20T00:00:00Z","limit":20,
    581        "fields":{"include":["id","properties.datetime","properties.eo:cloud_cover"]}}' \
    582   | jq '.features[] | {id, datetime:.properties.datetime, cloud:.properties["eo:cloud_cover"]}'
    583 # 2026-03-09 cloud 3%, 2026-03-14 cloud 11% — a usable before/after pair
    584 ```
    585 
    586 Pull both as B12/B8A/B4 GeoTIFFs through `/api/v1/process`, hash each, and record the scene IDs.
    587 The 14 March image shows a dark scar and a collapsed roof span on one silo where the 9 March image
    588 shows an intact structure.
    589 
    590 What you can assert: a thermal anomaly at the coordinate on the night of 11 March, from a sensor
    591 and not a report; no comparable detection in that pixel across the preceding year; and structural
    592 change visible between two named Sentinel-2 scenes bracketing the date. Three legs, two of them
    593 independent of all media reporting, each tied to a query, a retrieval time and a hash.
    594 
    595 What is not: the cause. Neither the hotspot nor the scar distinguishes a missile strike from a
    596 drone, an accident or deliberate arson, and attribution needs the remnant. If a photograph of
    597 debris surfaces, that goes to [OSMP](https://osmp.ngo/) for a markings comparison, and the
    598 identification is stated as consistent-with until a lot number is legible.
    599 
    600 What would falsify it: a second pre-event image showing the roof already damaged, a FIRMS quality
    601 flag or geolocation error placing the detections outside the terminal, or a longer baseline showing
    602 routine industrial heat at the same pixel. The imagery pair carries the structural-change claim;
    603 the thermal detections only narrow the time window and do not identify a cause.
    604 
    605 ## Broader catalogues
    606 
    607 - [Conflict OSINT](https://tools.osintnewsletter.com/tool-categories/conflict-osint)
    608 - [Environment & Wildlife OSINT](https://tools.osintnewsletter.com/tool-categories/environment-and-wildlife-osint)
    609 - [Public Media OSINT](https://tools.osintnewsletter.com/tool-categories/public-media-osint)
    610 
    611 
    612 ## More tools
    613 
    614 Further tools for this area from the OSINT Newsletter Tools Library ([Conflict OSINT](https://tools.osintnewsletter.com/tool-categories/conflict-osint), [Environment & Wildlife OSINT](https://tools.osintnewsletter.com/tool-categories/environment-and-wildlife-osint), [Public Media OSINT](https://tools.osintnewsletter.com/tool-categories/public-media-osint)), excluding those already listed above.
    615 
    616 | Tool | What it does |
    617 | --- | --- |
    618 | [1stHeadlines](https://mediabiasfactcheck.com/1stheadlines-bias-and-credibility/) | News aggregation and headline-monitoring site that brings together headlines from multiple news organisations in one searchable… |
    619 | [AllYouCanRead](https://www.allyoucanread.com/) | A global directory of newspapers, magazines and news websites covering more than 200 countries. |
    620 | [Bamqam](https://bamqam.com/) | A real-time geopolitical intelligence dashboard that aggregates military activity and conflict data into a map-based interface. |
    621 | [Combat Aircraft](https://www.combataircraft.com/) | Military aviation reference database providing aircraft specifications, operators, imagery, aviation news, and background… |
    622 | [Combined IUU Vessel List](https://iuu-vessels.org/Home/Search) | A free, searchable database that consolidates official Illegal, Unreported and Unregulated (IUU) fishing vessel lists published… |
    623 | [Country Studies](https://countrystudies.us/) | A free online reference library providing detailed country profiles covering history, politics, society, economics, security… |
    624 | [ECO-SOLVE Global Monitoring System](https://www.ecosolve.eco/dashboard) | An OSINT and AI-enabled monitoring platform for identifying and analysing online environmental crime, particularly illegal… |
    625 | [EJAtlas (Environmental Justice Atlas)](https://ejatlas.org/) | A global, collaborative database that documents environmental conflicts and environmental justice struggles. |
    626 | [Europe Media Monitor](https://media-monitor.europa.eu/home) | An automatic system that monitors global news media in near real time, aggregating multilingual news, alerts and trend analysis… |
    627 | [Geoconfirmed](https://geoconfirmed.org/) | A collaborative OSINT platform to help analysts verify and geolocate images, videos, and events from conflicts worldwide. |
    628 | [OSNT.IN](https://www.osnt.in/) | An AI-powered daily intelligence brief on the Russia-Ukraine war, synthesized from 200+ Ukrainian and Russian-language open… |
    629 
    630 ## Sources
    631 
    632 Both catalogues below are maintained by other people and are considerably larger than
    633 this page. Use them as the canonical index; this sheet is a working route through them.
    634 
    635 - [Bellingcat's Online Investigation Toolkit](https://bellingcat.gitbook.io/toolkit) — ~340 tools, each with its own
    636   review page covering cost, difficulty, requirements and limitations.
    637 - [OSINT Newsletter Tools Library](https://tools.osintnewsletter.com) — ~280 tools, organised by investigative goal.
    638 
    639 Neither publishes a licence, so nothing here is copied from them: tool names, one-line
    640 descriptions, cost flags and links are catalogue facts, and the method and commentary are
    641 this site's own. See [credits](/credits).