Definition
Intelligence Analysis is the systematic process of evaluating, interpreting, and synthesizing collected data from multiple sources to produce actionable intelligence products -- assessments, estimates, warnings, and recommendations that inform decision-making. Unlike raw data collection, analysis transforms unstructured observations into structured knowledge by applying analytic tradecraft: hypothesis generation, evidence weighing, confidence calibration, alternative analysis, and bias mitigation. The output is not merely a summary of collected data but a reasoned judgment about what the data means, what it implies for the future, and what actions it warrants.
In the intelligence community, analysis is the phase of the intelligence cycle where collected information becomes intelligence. The distinction is critical: information is raw, unprocessed, and context-free; intelligence is processed, evaluated, and contextualized for a specific consumer's needs. A domain registration record is information. An assessment that a threat actor is building infrastructure for a phishing campaign targeting financial institutions, based on patterns across domain registrations, certificate issuance, and historical behavior -- that is intelligence.
Overview
Intelligence analysis operates within the broader intelligence cycle, which comprises planning and direction, collection, processing, analysis, and dissemination. Analysis is the phase where human judgment (or increasingly, automated reasoning systems) transforms processed data into intelligence products. The quality of analysis depends on the quality of collection, but excellent collection cannot compensate for poor analysis, and vice versa.
The Analysis Spectrum
Analysis exists on a spectrum from descriptive to predictive to prescriptive:
| Level | Purpose | Output | Example |
|---|---|---|---|
| Descriptive | What happened | Situation reports, entity profiles | "Company X registered 14 domains in 48 hours" |
| Diagnostic | Why it happened | Root cause assessments | "Domain registration pattern matches infrastructure staging for credential harvesting" |
| Predictive | What will happen | Threat forecasts, trend analysis | "Based on historical patterns, campaign launch expected within 7-14 days" |
| Prescriptive | What to do | Recommendations, action items | "Block the following indicators, notify affected institutions, increase monitoring" |
The Prismatic Platform supports all four levels through its automated analysis pipelines, with human analyst oversight at the diagnostic and prescriptive levels where judgment is most critical.
Structured Analytic Techniques
Professional intelligence analysis employs Structured Analytic Techniques (SATs) to mitigate cognitive biases and improve analytic rigor. Key techniques include:
- Analysis of Competing Hypotheses (ACH): Systematically evaluates evidence against multiple hypotheses rather than seeking confirmation of a single hypothesis
- Key Assumptions Check: Identifies and challenges the assumptions underlying an analytic judgment
- Red Team Analysis: Deliberately adopts an adversarial perspective to identify vulnerabilities in assessments
- Indicators and Warnings (I&W): Defines observable indicators that would signal a change in assessed conditions
- Weighted Evidence Assessment: Assigns reliability and relevance scores to individual evidence items
Technical Details
The Analytic Process Model
Intelligence analysis in automated systems follows a structured pipeline:
Collection → Normalization → Enrichment → Correlation → Hypothesis Generation
→ Evidence Weighing → Confidence Calibration → Assessment Production → Dissemination
Each stage has specific technical requirements:
Normalization converts heterogeneous source data into a common schema. A domain record from WHOIS, a company record from ARES, and a certificate from CT logs must all be representable in a unified entity model.
Enrichment augments normalized records with contextual data: geolocation for IP addresses, industry classification for companies, historical behavior profiles for entities.
Correlation identifies relationships between entities across sources. This is where entity resolution is critical -- determining that "Acme Corp" in one source, "ACME Corporation s.r.o." in another, and a registrant email "admin@acme-corp.cz" in a third all refer to the same entity.
Confidence Calibration assigns probability estimates to analytic judgments using a standardized vocabulary:
| Term | Probability Range | Numeric Score |
|---|---|---|
| Almost Certain | 95-99% | 0.95-0.99 |
| Very Likely | 80-95% | 0.80-0.95 |
| Likely | 55-80% | 0.55-0.80 |
| Roughly Even | 45-55% | 0.45-0.55 |
| Unlikely | 20-45% | 0.20-0.45 |
| Very Unlikely | 5-20% | 0.05-0.20 |
| Remote | 1-5% | 0.01-0.05 |
Temporal Analysis
Intelligence analysis must account for temporal dimensions -- the age, freshness, and decay rate of information:
defmodule PrismaticIntelligence.TemporalAnalysis do
@moduledoc """
Temporal decay and freshness scoring for intelligence assessments.
Older information receives lower confidence weights unless corroborated
by recent collection.
"""
@type temporal_weight :: %{
source_timestamp: DateTime.t(),
collection_timestamp: DateTime.t(),
decay_function: :linear | :exponential | :step,
half_life_hours: pos_integer(),
weight: float()
}
@spec calculate_temporal_weight(DateTime.t(), keyword()) :: float()
def calculate_temporal_weight(source_timestamp, opts \\ []) do
half_life = Keyword.get(opts, :half_life_hours, 168)
decay_fn = Keyword.get(opts, :decay_function, :exponential)
hours_elapsed = DateTime.diff(DateTime.utc_now(), source_timestamp, :hour)
case decay_fn do
:exponential -> :math.exp(-0.693 * hours_elapsed / half_life)
:linear -> max(0.0, 1.0 - hours_elapsed / (half_life * 2))
:step -> if hours_elapsed <= half_life, do: 1.0, else: 0.5
end
end
@spec apply_temporal_weights(list(map()), keyword()) :: list(map())
def apply_temporal_weights(evidence_items, opts \\ []) do
Enum.map(evidence_items, fn item ->
weight = calculate_temporal_weight(item.timestamp, opts)
Map.put(item, :temporal_weight, weight)
end)
end
endImplementation in Prismatic Platform
The Prismatic Platform implements intelligence analysis through a multi-layered architecture that combines automated processing with structured analytic frameworks. The analysis engine operates as an OTP application within the umbrella, leveraging GenServer processes for stateful analysis sessions and supervised pipelines for fault-tolerant processing.
Analysis Pipeline Architecture
defmodule PrismaticIntelligence.AnalysisPipeline do
@moduledoc """
Orchestrates the intelligence analysis pipeline from raw collected data
through enrichment, correlation, and assessment production.
Each stage is implemented as a supervised GenServer that processes
items from a Broadway-style pipeline with backpressure support.
"""
use GenServer
@type pipeline_config :: %{
sources: list(atom()),
enrichment_modules: list(module()),
correlation_engine: module(),
assessment_template: atom(),
confidence_threshold: float(),
temporal_decay: keyword()
}
@type analysis_result :: %{
assessment_id: String.t(),
subject: String.t(),
findings: list(map()),
confidence: float(),
evidence_count: pos_integer(),
sources_consulted: list(atom()),
analytic_notes: list(String.t()),
produced_at: DateTime.t()
}
@spec start_link(pipeline_config()) :: GenServer.on_start()
def start_link(config) do
GenServer.start_link(__MODULE__, config, name: via_tuple(config))
end
@spec analyze(GenServer.server(), String.t(), keyword()) ::
{:ok, analysis_result()} | {:error, term()}
def analyze(pipeline, subject, opts \\ []) do
timeout = Keyword.get(opts, :timeout, 30_000)
GenServer.call(pipeline, {:analyze, subject, opts}, timeout)
end
@impl true
def init(config) do
state = %{
config: config,
active_analyses: %{},
completed_count: 0,
error_count: 0
}
{:ok, state}
end
@impl true
def handle_call({:analyze, subject, opts}, from, state) do
analysis_id = generate_analysis_id(subject)
task =
Task.Supervisor.async_nolink(
PrismaticIntelligence.TaskSupervisor,
fn -> execute_analysis(state.config, subject, analysis_id, opts) end
)
active = Map.put(state.active_analyses, task.ref, {from, analysis_id})
{:noreply, %{state | active_analyses: active}}
end
@impl true
def handle_info({ref, result}, state) when is_reference(ref) do
Process.demonitor(ref, [:flush])
case Map.pop(state.active_analyses, ref) do
{{from, _analysis_id}, active} ->
GenServer.reply(from, {:ok, result})
{:noreply, %{state | active_analyses: active, completed_count: state.completed_count + 1}}
{nil, _active} ->
{:noreply, state}
end
end
@impl true
def handle_info({:DOWN, ref, :process, _pid, reason}, state) do
case Map.pop(state.active_analyses, ref) do
{{from, _analysis_id}, active} ->
GenServer.reply(from, {:error, {:analysis_failed, reason}})
{:noreply, %{state | active_analyses: active, error_count: state.error_count + 1}}
{nil, _active} ->
{:noreply, state}
end
end
defp execute_analysis(config, subject, analysis_id, opts) do
with {:ok, raw_data} <- collect_from_sources(config.sources, subject),
{:ok, enriched} <- enrich_data(config.enrichment_modules, raw_data),
{:ok, correlated} <- correlate_entities(config.correlation_engine, enriched),
{:ok, assessment} <- produce_assessment(correlated, config, analysis_id, opts) do
assessment
end
end
defp collect_from_sources(sources, subject) do
results =
sources
|> Task.async_stream(fn source -> source.collect(subject) end,
max_concurrency: 10,
timeout: 15_000
)
|> Enum.reduce([], fn
{:ok, {:ok, data}}, acc -> [data | acc]
{:ok, {:error, _reason}}, acc -> acc
{:exit, _reason}, acc -> acc
end)
{:ok, List.flatten(results)}
end
defp enrich_data(modules, raw_data) do
enriched =
Enum.reduce(modules, raw_data, fn module, data ->
case module.enrich(data) do
{:ok, enriched_data} -> enriched_data
{:error, _reason} -> data
end
end)
{:ok, enriched}
end
defp correlate_entities(engine, enriched_data) do
engine.correlate(enriched_data)
end
defp produce_assessment(correlated, config, analysis_id, opts) do
confidence = calculate_composite_confidence(correlated, config)
threshold = Keyword.get(opts, :confidence_threshold, config.confidence_threshold)
if confidence >= threshold do
assessment = %{
assessment_id: analysis_id,
subject: correlated.subject,
findings: correlated.findings,
confidence: confidence,
evidence_count: length(correlated.evidence),
sources_consulted: correlated.sources,
analytic_notes: correlated.notes,
produced_at: DateTime.utc_now()
}
{:ok, assessment}
else
{:error, {:insufficient_confidence, confidence, threshold}}
end
end
defp calculate_composite_confidence(correlated, config) do
correlated.evidence
|> PrismaticIntelligence.TemporalAnalysis.apply_temporal_weights(config.temporal_decay)
|> Enum.map(& &1.temporal_weight * &1.source_reliability)
|> then(fn weights ->
if Enum.empty?(weights), do: 0.0, else: Enum.sum(weights) / length(weights)
end)
end
defp generate_analysis_id(subject) do
hash = :crypto.hash(:sha256, "#{}-#{System.system_time(:nanosecond)}")
"IA-" <> Base.encode16(hash, case: :lower) |> String.slice(0, 16)
end
defp via_tuple(config) do
{:via, Registry, {PrismaticIntelligence.Registry, {:pipeline, config.assessment_template}}}
end
endAnalysis of Competing Hypotheses Engine
The platform implements ACH as a core structured analytic technique:
defmodule PrismaticIntelligence.ACH do
@moduledoc """
Analysis of Competing Hypotheses (ACH) implementation.
Systematically evaluates evidence against multiple hypotheses
to identify the most supported assessment while flagging
diagnostic evidence that distinguishes between hypotheses.
"""
@type hypothesis :: %{
id: String.t(),
description: String.t(),
prior_probability: float()
}
@type evidence_item :: %{
id: String.t(),
description: String.t(),
source: atom(),
reliability: float(),
relevance: float(),
timestamp: DateTime.t()
}
@type consistency_rating :: :very_consistent | :consistent | :neutral |
:inconsistent | :very_inconsistent
@type ach_matrix :: %{
hypotheses: list(hypothesis()),
evidence: list(evidence_item()),
ratings: %{{String.t(), String.t()} => consistency_rating()},
scores: %{String.t() => float()},
diagnosticity: %{String.t() => float()}
}
@spec build_matrix(list(hypothesis()), list(evidence_item())) :: ach_matrix()
def build_matrix(hypotheses, evidence) do
ratings = generate_ratings(hypotheses, evidence)
scores = calculate_hypothesis_scores(hypotheses, evidence, ratings)
diagnosticity = calculate_diagnosticity(hypotheses, evidence, ratings)
%{
hypotheses: hypotheses,
evidence: evidence,
ratings: ratings,
scores: scores,
diagnosticity: diagnosticity
}
end
@spec most_supported(ach_matrix()) :: {:ok, hypothesis()} | {:error, :inconclusive}
def most_supported(matrix) do
case Enum.max_by(matrix.hypotheses, &Map.get(matrix.scores, &1.id, 0.0)) do
nil -> {:error, :inconclusive}
best -> {:ok, best}
end
end
@spec diagnostic_evidence(ach_matrix()) :: list(evidence_item())
def diagnostic_evidence(matrix) do
matrix.evidence
|> Enum.filter(fn ev -> Map.get(matrix.diagnosticity, ev.id, 0.0) > 0.6 end)
|> Enum.sort_by(fn ev -> Map.get(matrix.diagnosticity, ev.id, 0.0) end, :desc)
end
defp generate_ratings(hypotheses, evidence) do
for h <- hypotheses, e <- evidence, into: %{} do
{{h.id, e.id}, rate_consistency(h, e)}
end
end
defp rate_consistency(_hypothesis, _evidence) do
# Production implementation uses NLP and domain-specific rules
:neutral
end
defp calculate_hypothesis_scores(hypotheses, evidence, ratings) do
for h <- hypotheses, into: %{} do
score =
evidence
|> Enum.map(fn e ->
rating = Map.get(ratings, {h.id, e.id}, :neutral)
rating_to_numeric(rating) * e.reliability * e.relevance
end)
|> Enum.sum()
{h.id, score}
end
end
defp calculate_diagnosticity(hypotheses, evidence, ratings) do
for e <- evidence, into: %{} do
scores_for_evidence =
Enum.map(hypotheses, fn h ->
rating = Map.get(ratings, {h.id, e.id}, :neutral)
rating_to_numeric(rating)
end)
variance =
if length(scores_for_evidence) > 1 do
mean = Enum.sum(scores_for_evidence) / length(scores_for_evidence)
scores_for_evidence
|> Enum.map(fn s -> (s - mean) * (s - mean) end)
|> Enum.sum()
|> Kernel./(length(scores_for_evidence))
else
0.0
end
{e.id, :math.sqrt(variance)}
end
end
defp rating_to_numeric(:very_consistent), do: 2.0
defp rating_to_numeric(:consistent), do: 1.0
defp rating_to_numeric(:neutral), do: 0.0
defp rating_to_numeric(:inconsistent), do: -1.0
defp rating_to_numeric(:very_inconsistent), do: -2.0
endIntegration with OSINT Pipelines
The analysis engine integrates directly with the platform's OSINT collection infrastructure. When an OSINT pipeline completes collection for a target, the analysis engine is automatically invoked:
- Entity Resolution: The entity resolution engine consolidates collected records into a unified entity graph
- Risk Scoring: The risk score module calculates composite risk based on multiple indicators
- Threat Assessment: The threat assessment framework evaluates potential threats based on capability, intent, and opportunity
- Assessment Production: Final intelligence products are generated with confidence ratings and analytic notes
Comparison with Alternatives
| Platform | Approach | Strengths | Limitations |
|---|---|---|---|
| Prismatic | Automated pipeline + SATs | OTP fault tolerance, Elixir concurrency, integrated entity resolution | Specialized for OSINT sources |
| Palantir Gotham | Graph-based visual analysis | Massive dataset handling, government adoption | Proprietary, expensive, requires dedicated analysts |
| Maltego | Graph link analysis | Visual entity mapping, many transforms | Manual-heavy, limited automation |
| Recorded Future | ML-driven threat intelligence | Real-time threat feeds, NLP analysis | SaaS-only, limited customization |
| IBM i2 | Analyst notebook paradigm | Established methodology, law enforcement standard | Legacy architecture, steep learning curve |
| Analyst's Notebook | Timeline and link analysis | Temporal analysis, courtroom-ready output | Desktop-only, no automation |
Prismatic's advantage is architectural: by building intelligence analysis as OTP processes within an Elixir umbrella, the platform achieves fault-tolerant, concurrent analysis that scales horizontally without the complexity of distributed Java or Python systems.
Best Practices
- Apply Structured Analytic Techniques: Never rely on intuition alone. Use ACH, key assumptions checks, and red team analysis for every significant assessment
- Calibrate Confidence: Use standardized probability language. "Likely" means 55-80%, not "I think so"
- Document Assumptions: Every assessment rests on assumptions. Make them explicit so they can be challenged
- Preserve Contradictions: Following the NABLA Infinity framework, contradictory evidence must be preserved, not discarded
- Separate Collection from Analysis: Analysts should not direct their own collection -- this introduces confirmation bias
- Apply Temporal Decay: Older evidence receives lower weight unless corroborated by recent collection
- Use the Triple-Check Pattern: Critical assessments must pass the triple-check validation engine with three independent source corroboration
- Version Assessments: Intelligence is perishable. Assessments must be versioned and updated as new evidence arrives
Common Pitfalls
- Confirmation Bias: Seeking evidence that confirms an existing hypothesis while ignoring contradictory data. ACH mitigates this by requiring explicit evaluation of evidence against all hypotheses
- Mirror Imaging: Assuming the adversary thinks and acts the same way you do. Red team analysis helps counter this
- Anchoring: Over-weighting the first piece of evidence received. Temporal weighting and structured evidence evaluation reduce anchoring effects
- Groupthink: Convergence on a single assessment without genuine deliberation. The platform's contradiction preservation axiom (from NABLA Infinity) explicitly prevents this
- Satisficing: Stopping analysis when a "good enough" explanation is found rather than evaluating all hypotheses. ACH's exhaustive matrix approach prevents premature closure
- Source Fixation: Over-relying on a single high-quality source at the expense of multi-source corroboration
- Recency Bias: Over-weighting recent evidence while discounting historical patterns. Balanced temporal decay functions address this
- Ignoring Base Rates: Failing to account for the prior probability of events when evaluating new evidence
Use Cases
Corporate Due Diligence
When conducting due diligence on a potential business partner, the analysis engine collects data from Czech business registries (ARES, Justice.cz), international company databases, sanctions lists, and open web sources. The ACH framework evaluates competing hypotheses about the entity's legitimacy, beneficial ownership structure, and risk profile. The output is a structured assessment with confidence ratings suitable for compliance documentation.
Cyber Threat Intelligence
The platform's cyber threat intelligence capability uses intelligence analysis to assess threat actor campaigns. Indicators of compromise (IoCs) are collected from multiple sources, correlated through entity resolution, and analyzed to produce threat assessments with predicted timelines and recommended mitigations.
Attack Surface Monitoring
Within the EASM framework, intelligence analysis continuously evaluates the organization's external attack surface. Changes in DNS records, certificate issuance, and exposed services are analyzed to produce risk-scored assessments that drive security ratings through Prismatic Perimeter.
Sanctions Compliance
For sanctions screening and AML compliance, the analysis engine evaluates matches against sanctions lists using fuzzy matching and contextual analysis to reduce false positives while maintaining compliance sensitivity.
Related Concepts
- OSINT -- The discipline of collecting intelligence from publicly available sources, providing the raw material for analysis
- Intelligence Fusion -- The process of combining intelligence from multiple sources and disciplines into a unified picture
- Entity Resolution -- Determining that records from different sources refer to the same real-world entity
- Risk Score -- Quantified risk assessment produced by analysis pipelines
- Due Diligence -- Investigative process that relies on intelligence analysis for assessment production
- Cyber Threat Intelligence -- Specialized analysis focused on adversarial cyber operations
- Threat Assessment -- Evaluation of potential threats based on capability, intent, and opportunity
- Intelligence Platform -- The comprehensive system within which analysis operates
- Knowledge Graph -- Graph-based knowledge representation that supports analytic reasoning
- Triple Check -- Three-source corroboration validation for critical assessments
See Also
- OSINT -- Collection discipline feeding the analysis pipeline
- Intelligence Fusion -- Multi-source integration methodology
- Hawkeye -- Visitor intelligence system using analysis techniques
- EASM -- External Attack Surface Management leveraging continuous analysis
- Risk Assessment -- Broader risk evaluation framework
- Prismatic Perimeter -- Security ratings driven by intelligence analysis
Connect & Contribute
Created by Tomáš Korcak (korczis) | Open Source under GHL