LLM SECURITY TELEMETRY · SOURCE GUIDE

01. Instruction injection

Where this concern meets the GGUF execution graph

The highlighted annotations locate attack entry, possible influence, constraints and observable effects for this concern. They are source-based hypotheses, not a trace of a demonstrated attack. GGUF supplies weights and metadata; llama.cpp builds and executes the computation graph.

Source snapshot: llama.cpp 5266f24da75dc449bd56cbed7addb9c8e4a6a73e. Concrete Llama architecture, ordinary generation path, non-fused attention as configured by this driver. Other architectures and fused kernels can use different graphs. All code below is embedded and expandable; no network or inference is required.

STAGE 01

GGUF → model weights, vocabulary and architecture

GGUF is a model file. The loader reads its metadata and tensors; C++ architecture code constructs the executable graph.

MODEL BASELINE: keep the GGUF identity and inference revision fixed. This concern does not demonstrate an attack on the GGUF loader or a modification of model weights.

llama.cpp implementation

llama.cpp/src/llama-model-loader.cpp:562–580View code
    if (!fname.empty()) {        // Load the main GGUF        struct ggml_context * ctx = NULL;        struct gguf_init_params params = {            /*.no_alloc = */ true,            /*.ctx      = */ &ctx,        };        metadata_ptr.reset(gguf_init_from_file(fname.c_str(), params));        metadata = metadata_ptr.get();        if (metadata == nullptr) {            throw std::runtime_error(format("%s: failed to load model from %s", __func__, fname.c_str()));        }        get_key(llm_kv(LLM_KV_GENERAL_ARCHITECTURE), arch_name, false);        llm_kv = LLM_KV(llm_arch_from_string(arch_name));        files.emplace_back(new llama_file(fname.c_str(), "rb", use_direct_io));        contexts.emplace_back(ctx);

llama.cpp implementation

llama.cpp/src/llama.cpp:343–371View code
        model->hparams.vocab_only = params.vocab_only;        model->hparams.no_alloc   = params.no_alloc;        try {            model->load_hparams(ml);        } catch(const std::exception & e) {            throw std::runtime_error("error loading model hyperparameters: " + std::string(e.what()));        }        if (model->arch == LLM_ARCH_CLIP) {            throw std::runtime_error("CLIP cannot be used as main model, use it with --mmproj instead");        }        try {            model->load_vocab(ml);        } catch(const std::exception & e) {            throw std::runtime_error("error loading model vocabulary: " + std::string(e.what()));        }        model->load_stats(ml);        model->print_info();        if (params.vocab_only) {            LLAMA_LOG_INFO("%s: vocab only - skipping tensors\n", __func__);            return {0, model_ptr.release()};        }        if (!model->load_tensors(ml)) {            return {-2, nullptr};        }
STAGE 02

Rendered text → token IDs

The caller supplies the final prompt. llama_tokenize delegates to the loaded vocabulary; tokenization itself does not execute the transformer.

ATTACK ENTRY: an instruction-like passage is inserted in untrusted source text before tokenization. Region labels are supplied separately by the caller.

llama.cpp implementation

llama.cpp/src/llama-vocab.cpp:4410–4419View code
int32_t llama_tokenize(    const struct llama_vocab * vocab,                  const char * text,                     int32_t   text_len,                 llama_token * tokens,                     int32_t   n_tokens_max,                        bool   add_special,                        bool   parse_special) {    return vocab->tokenize(text, text_len, tokens, n_tokens_max, add_special, parse_special);}

Driver: read the rendered prompt

src/cst_capture.cpp:83–91View code
int main(int argc,char ** argv){    if(argc!=2){std::cerr<<"Usage: cst-capture config.json\n";return 2;}    try {        json j=json::parse(read_file(argv[1]));        std::string model_path=j.at("model"),prompt=read_file(j.at("prompt_file"));        std::string log=j.value("log_path",std::string("trial.cstbin")),jsonl=j.value("jsonl_path",std::string("trial.telemetry.jsonl"));        std::string run=j.value("run_id",std::string("local"));        int max_tokens=j.value("max_tokens",32),nctx=j.value("context_size",4096),stride=j.value("score_stride",1);        if(max_tokens<=0 || nctx<=0 || stride<=0)throw std::runtime_error("invalid token/context/score limits");
STAGE 03

Decode → build or reuse graph → set current inputs

process_ubatch applies memory state, builds or reuses the graph, sets new inputs and requests graph computation. Reusing topology still computes the new input.

EXECUTION ENTRY: the current prefix and context state reach the model here. Building or reusing topology is not itself an attack; the relevant influence is identified in the stages below.

llama.cpp implementation

llama.cpp/src/llama-context.cpp:1334–1403View code
llm_graph_result * llama_context::process_ubatch(const llama_ubatch & ubatch, llm_graph_type gtype, llama_memory_context_i * mctx, ggml_status & ret) {    if (mctx && !mctx->apply()) {        LLAMA_LOG_ERROR("%s: failed to apply memory context\n", __func__);        ret = GGML_STATUS_FAILED;        return nullptr;    }    auto * res = gf_res_prev.get();    auto * gf  = res->get_gf();    // the new graph parameters    // in order to correctly reuse a graph, it's full topology has to be uniquely determined by these parameters    const auto gparams = graph_params(res, ubatch, mctx, gtype);    if (!graph_reuse_disable && res->can_reuse(gparams)) {        //LLAMA_LOG_DEBUG("%s: reusing previous graph\n", __func__);        // with pipeline parallelism, the previous graph_compute_async may still be running        // on the GPU. we must synchronize before set_inputs to avoid overwriting input tensors        // that the previous compute is still reading.        if (cparams.pipeline_parallel) {            ggml_backend_sched_synchronize(sched.get());        }        n_reused++;    } else {        res->reset();        ggml_backend_sched_reset(sched.get());        ggml_backend_sched_set_eval_callback(sched.get(), cparams.cb_eval, cparams.cb_eval_user_data);        //const auto t_start_us = ggml_time_us();        gf = model.build_graph(gparams);        //LLAMA_LOG_INFO("graph build time: %.3f ms\n", (ggml_time_us() - t_start_us)/1000.0);        if (!gf) {            LLAMA_LOG_ERROR("%s: failed to initialize graph\n", __func__);            ret = GGML_STATUS_FAILED;            return nullptr;        }        if (!ggml_backend_sched_alloc_graph(sched.get(), gf)) {            LLAMA_LOG_ERROR("%s: failed to allocate graph\n", __func__);            ret = GGML_STATUS_ALLOC_FAILED;            return nullptr;        }    }    // set the input data for the input tensors    {        //const auto t_start_us = ggml_time_us();        // FIXME this call causes a crash if any model inputs were not used in the graph and were therefore not allocated        res->set_inputs(&ubatch);        //LLAMA_LOG_INFO("graph set inputs time: %.3f ms\n", (ggml_time_us() - t_start_us)/1000.0);    }    const auto status = graph_compute(res->get_gf(), ubatch.n_tokens > 1);    if (status != GGML_STATUS_SUCCESS) {        LLAMA_LOG_ERROR("%s: failed to compute graph, compute status: %d\n", __func__, status);        ret = status;        return nullptr;    }    ret = GGML_STATUS_SUCCESS;    return res;

llama.cpp implementation

llama.cpp/src/llama-model.cpp:2673–2690View code
ggml_cgraph * llama_model::build_graph(const llm_graph_params & params) const {    std::unique_ptr<llm_graph_context> llm = build_arch_graph(params);    // add on pooling layer    llm->build_pooling(cls, cls_b, cls_out, cls_out_b, cls_norm);    // add backend sampling layers (if any)    llm->build_sampling();    // if the gguf model was converted with --sentence-transformers-dense-modules    // there will be two additional dense projection layers    // dense linear projections are applied after pooling    // TODO: move reranking logic here and generalize    llm->build_dense_out(dense_2_out_layers, dense_2_out_layers_b, dense_3_out_layers);    llm->res->set_outputs(params);    return llm->res->get_gf();

Driver: decode each prompt token

src/cst_capture.cpp:176–182View code
        cst_set_position(0,0,0,0,"prefill");cst_log_prompt(input.data(),(int)input.size(),prompt.c_str());        auto trial_start=Clock::now(),start=trial_start;        std::vector<int32_t> keys;        for(size_t i=0;i<input.size();++i){            cst_set_position(0,0,(int)i,0,"prefill");keys.push_back((int)i);cst_set_attention_key_positions(keys.data(),(int)keys.size());            decode_one(ctx.get(),input[i]);        }

Inside the Llama forward graph

Tensor dependency order: embeddings → per-layer attention and FFN → final logits. K/V, attention and FFN repeat for each layer. The backend executes these operations during decode; graph construction alone does not compute their values.

STAGE 04

Token embeddings + positions

Token IDs select rows of the GGUF embedding matrix. The Llama graph supplies positions and enters its transformer-layer loop.

INPUT REPRESENTATION: tokens from the source described above become embedding vectors and positional inputs. The embedding lookup does not enforce source trust or label a token as an attack.

llama.cpp implementation

llama.cpp/src/llama-graph.cpp:2303–2328View code
ggml_tensor * llm_graph_context::build_inp_embd(ggml_tensor * tok_embd) const {    const int64_t n_embd_inp = hparams.n_embd_inp();    const int64_t n_embd     = hparams.n_embd;    assert(n_embd_inp >= n_embd);    auto inp = std::make_unique<llm_graph_input_embd>(n_embd_inp);    inp->tokens = ggml_new_tensor_1d(ctx0, GGML_TYPE_I32, ubatch.n_tokens);    cb(inp->tokens, "inp_tokens", -1);    ggml_set_input(inp->tokens);    res->t_inp_tokens = inp->tokens;    inp->embd = ggml_new_tensor_2d(ctx0, GGML_TYPE_F32, n_embd_inp, ubatch.n_tokens);    cb(inp->embd, "inp_embd", -1);    ggml_set_input(inp->embd);    // select one of the 2 inputs, based on the batch contents    // ref: https://github.com/ggml-org/llama.cpp/pull/18550    std::array<ggml_tensor *, 2> inps;    // token embeddings path (ubatch.token != nullptr)    {        auto & cur = inps[0];        cur = ggml_get_rows(ctx0, tok_embd, inp->tokens);

llama.cpp implementation

llama.cpp/src/models/llama.cpp:108–131View code
    inpL = build_inp_embd(model.tok_embd);    // inp_pos - contains the positions    ggml_tensor * inp_pos = build_inp_pos();    using inp_attn_type = std::conditional_t<embed, llm_graph_input_attn_no_cache, llm_graph_input_attn_kv>;    inp_attn_type * inp_attn = nullptr;    if constexpr (embed) {        inp_attn = build_attn_inp_no_cache();    } else {        inp_attn = build_attn_inp_kv();    }    const float kq_scale = hparams.f_attention_scale == 0.0f ? 1.0f/sqrtf(float(n_embd_head)) : hparams.f_attention_scale;    ggml_tensor * inp_out_ids = build_inp_out_ids();    for (int il = 0; il < n_layer; ++il) {        res->t_layer_inp[il] = inpL;        ggml_tensor * inpSA = inpL;        // norm
STAGE 05

Per layer: Q/K/V + position encoding → KV cache

The graph computes Q/K/V, applies RoPE and adds K/V cache writes. Attention reads the available cache with a position mask.

The injected tokens contribute K/V state while they remain in context. This is ordinary inference state, not a modification of GGUF weights.

llama.cpp implementation

llama.cpp/src/models/llama.cpp:139–161View code
            // rope freq factors for llama3; may return nullptr for llama2 and other models            ggml_tensor * rope_factors = model.get_rope_factors(cparams, il);            // compute Q and K and RoPE them            auto [Qcur, Kcur, Vcur] = build_qkv(model.layers[il], cur,                    n_embd_head, n_head, n_head_kv, il);            Qcur = ggml_rope_ext(                    ctx0, Qcur, inp_pos, rope_factors,                    n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,                    ext_factor, attn_factor, beta_fast, beta_slow                    );            Kcur = ggml_rope_ext(                    ctx0, Kcur, inp_pos, rope_factors,                    n_rot, rope_type, n_ctx_orig, freq_base, freq_scale,                    ext_factor, attn_factor, beta_fast, beta_slow                    );            cb(Qcur, "Qcur", il);            cb(Kcur, "Kcur", il);            cb(Vcur, "Vcur", il);

llama.cpp implementation

llama.cpp/src/llama-graph.cpp:2815–2833View code
    const auto * mctx_cur = inp->mctx;    // store to KV cache    {        const auto & k_idxs = inp->get_k_idxs();        const auto & v_idxs = inp->get_v_idxs();        ggml_build_forward_expand(gf, mctx_cur->cpy_k(ctx0, k_cur, k_idxs, il));        ggml_build_forward_expand(gf, mctx_cur->cpy_v(ctx0, v_cur, v_idxs, il));    }    ggml_tensor * kq_mask = inp->get_kq_mask();    ggml_tensor * q = q_cur;    ggml_tensor * k = mctx_cur->get_k(ctx0, il);    ggml_tensor * v = mctx_cur->get_v(ctx0, il);    ggml_tensor * cur = build_attn_mha(q, k, v, kq_b, kq_mask, sinks, v_mla, 0, kq_scale, il);    cb(cur, "kqv_out", il);
STAGE 06

Per layer: QK scores → masked softmax → weighted V

On the non-fused path, kq_soft_max contains attention probabilities. Those weights mix value vectors into the attention output.

POSSIBLE INFLUENCE: a response query can attend to the injected passage. Measure region mass at corresponding heads and positions; high mass does not prove instruction following.

llama.cpp implementation

llama.cpp/src/llama-graph.cpp:2605–2610View code
        ggml_tensor * kq = ggml_mul_mat(ctx0, k, q);        cb(kq, "kq", il);        // note: this op tends to require high floating point range        //       while for some models F16 is enough, for others it is not, so we default to F32 here        ggml_mul_mat_set_prec(kq, GGML_PREC_F32);

llama.cpp implementation

llama.cpp/src/llama-graph.cpp:2633–2650View code
        if (kq_b) {            kq = ggml_add(ctx0, kq, kq_b);            cb(kq, "kq_plus_kq_b", il);        }        kq = ggml_soft_max_ext(ctx0, kq, kq_mask, kq_scale, hparams.f_max_alibi_bias);        ggml_soft_max_add_sinks(kq, sinks);        cb(kq, "kq_soft_max", il);        if (!v_trans) {            // note: avoid this branch            v = ggml_cont(ctx0, ggml_transpose(ctx0, v));            cb(v, "v_cont", il);        }        ggml_tensor * kqv = ggml_mul_mat(ctx0, v, kq);        cb(kqv, "kqv", il);
STAGE 07

Per layer: attention residual → FFN → layer output

Attention output is added to the residual, transformed by the FFN, then added again. l_out feeds the next layer; the layer loop repeats.

POSSIBLE INFLUENCE: attention mixes the passage into representations that propagate through residual and FFN layers. Compare l_out summaries; no individual layer is identified as an attack detector.

llama.cpp implementation

llama.cpp/src/models/llama.cpp:173–195View code
        }        if (il == n_layer - 1 && inp_out_ids) {            cur   = ggml_get_rows(ctx0,   cur, inp_out_ids);            inpSA = ggml_get_rows(ctx0, inpSA, inp_out_ids);        }        ggml_tensor * ffn_inp = ggml_add(ctx0, cur, inpSA);        cb(ffn_inp, "ffn_inp", il);        // feed-forward network (non-MoE)        if (model.layers[il].ffn_gate_inp == nullptr) {            cur = build_norm(ffn_inp,                    model.layers[il].ffn_norm, NULL,                    LLM_NORM_RMS, il);            cb(cur, "ffn_norm", il);            cur = build_ffn(cur,                    model.layers[il].ffn_up,   model.layers[il].ffn_up_b,   model.layers[il].ffn_up_s,                    model.layers[il].ffn_gate, model.layers[il].ffn_gate_b, model.layers[il].ffn_gate_s,                    model.layers[il].ffn_down, model.layers[il].ffn_down_b, model.layers[il].ffn_down_s,                    NULL,                    LLM_FFN_SILU, LLM_FFN_PAR, il);            cb(cur, "ffn_out", il);

llama.cpp implementation

llama.cpp/src/models/llama.cpp:220–228View code
        cur = ggml_add(ctx0, cur, ffn_inp);        cb(cur, "ffn_out", il);        cur = build_cvec(cur, il);        cb(cur, "l_out", il);        // input for next layer        inpL = cur;    }
STAGE 08

Final normalization → vocabulary logits

After the final layer, output normalization and the GGUF output projection produce result_output / t_logits.

OBSERVE: compare raw distributions at an aligned response boundary for a shift away from the legitimate task.

llama.cpp implementation

llama.cpp/src/models/llama.cpp:230–246View code
    cur = build_norm(cur,            model.output_norm, NULL,            LLM_NORM_RMS, -1);    cb(cur, "result_norm", -1);    res->t_embd = cur;    if constexpr (!embed) {        // lm_head        cur = build_lora_mm(model.output, cur, model.output_s);        cb(cur, "result_output", -1);        res->t_logits = cur;    }    ggml_build_forward_expand(gf, cur);
STAGE 09

Backend executes these graph operations; callbacks observe tensors

The preceding boxes describe tensor dependencies. Numerics execute through this scheduler, which computes graph ranges, synchronizes and invokes requested observation callbacks during execution.

The backend computes the same kinds of operations in both conditions. Callbacks reveal tensors; they neither execute the injected instruction as code nor classify attack success.

llama.cpp implementation

llama.cpp/src/llama-context.cpp:2491–2518View code
ggml_status llama_context::graph_compute(            ggml_cgraph * gf,                   bool   batched) {    int n_threads        = batched ? cparams.n_threads_batch : cparams.n_threads;    ggml_threadpool_t tp = batched ? threadpool_batch        : threadpool;    if (backend_cpu != nullptr) {        auto * reg = ggml_backend_dev_backend_reg(ggml_backend_get_device(backend_cpu));        auto * set_threadpool_fn = (decltype(ggml_backend_cpu_set_threadpool) *) ggml_backend_reg_get_proc_address(reg, "ggml_backend_cpu_set_threadpool");        if (set_threadpool_fn) {            set_threadpool_fn(backend_cpu, tp);        }    }    // set the number of threads for all the backends    for (const auto & set_n_threads_fn : set_n_threads_fns) {        set_n_threads_fn.second(set_n_threads_fn.first, n_threads);    }    auto status = ggml_backend_sched_graph_compute_async(sched.get(), gf);    if (status != GGML_STATUS_SUCCESS) {        LLAMA_LOG_ERROR("%s: ggml_backend_sched_graph_compute_async failed with error %d\n", __func__, status);    }    // fprintf(stderr, "splits: %d\n", ggml_backend_sched_get_n_splits(sched));    return status;}

llama.cpp implementation

llama.cpp/ggml/src/ggml-backend.cpp:1802–1838View code
        if (!sched->callback_eval) {            enum ggml_status ec = ggml_backend_graph_compute_async(split_backend, &split->graph);            if (ec != GGML_STATUS_SUCCESS) {                return ec;            }        } else {            // similar to ggml_backend_compare_graph_backend            for (int j0 = 0; j0 < split->graph.n_nodes; j0++) {                struct ggml_tensor * t = split->graph.nodes[j0];                // check if the user needs data from this node                bool need = sched->callback_eval(t, true, sched->callback_eval_user_data);                int j1 = j0;                // determine the range [j0, j1] of nodes that can be computed together                while (!need && j1 < split->graph.n_nodes - 1) {                    t = split->graph.nodes[++j1];                    need = sched->callback_eval(t, true, sched->callback_eval_user_data);                }                struct ggml_cgraph gv = ggml_graph_view(&split->graph, j0, j1 + 1);                enum ggml_status ec = ggml_backend_graph_compute_async(split_backend, &gv);                if (ec != GGML_STATUS_SUCCESS) {                    return ec;                }                // TODO: pass backend to the callback, then the user can decide if they want to synchronize                ggml_backend_synchronize(split_backend);                if (need && !sched->callback_eval(t, false, sched->callback_eval_user_data)) {                    break;                }                j0 = j1;            }

llama.cpp implementation

llama.cpp/ggml/src/ggml-backend.cpp:461–464View code
enum ggml_status ggml_backend_graph_compute_async(ggml_backend_t backend, struct ggml_cgraph * cgraph) {    GGML_ASSERT(backend);    return backend->iface.graph_compute(backend, cgraph);}
STAGE 10

Raw logits → grammar / sampler stages → selected token

This driver applies its configured samplers after decode. llama_sampler_apply dispatches each stage; a grammar stage filters the candidate distribution.

Keep the sampler chain fixed across clean and injected conditions so filtering and random selection are not mistaken for an input effect.

llama.cpp implementation

llama.cpp/src/llama-sampler.cpp:382–389View code
void llama_sampler_apply(struct llama_sampler * smpl, struct llama_token_data_array * cur_p) {    if (!smpl) {        return;    }    GGML_ASSERT(smpl->iface->apply);    smpl->iface->apply(smpl, cur_p);}

llama.cpp implementation

llama.cpp/src/llama-sampler.cpp:2680–2685View code
static void llama_sampler_grammar_apply(struct llama_sampler * smpl, llama_token_data_array * cur_p) {    auto * ctx = (llama_sampler_grammar *) smpl->ctx;    if (ctx->grammar) {        llama_grammar_apply_impl(*ctx->grammar, cur_p);    }}
STAGE 11

Selected token → output bytes → next decode ↺

llama_token_to_piece returns the token bytes. The caller records them and feeds the selected token into the next decode when another prediction is needed.

BEHAVIORAL EVIDENCE: inspect actual generated bytes for the specified task deviation. This is where following the injected instruction can become visible.

llama.cpp implementation

llama.cpp/src/llama-vocab.cpp:4421–4429View code
int32_t llama_token_to_piece(    const struct llama_vocab * vocab,                 llama_token   token,                        char * buf,                     int32_t   length,                     int32_t   lstrip,                        bool   special) {    return vocab->token_to_piece(token, buf, length, lstrip, special);}

Driver: record bytes and feed back the selected token

src/cst_capture.cpp:219–240View code
            for(auto & s:samplers)llama_sampler_accept(s.get(),id);            std::string text=piece(vocab,id);cst_log_token_bytes(text.data(),text.size());            event("special_token",{{"token_id",id},{"is_eog",llama_vocab_is_eog(vocab,id)},                  {"eos_raw_logprob",llama_vocab_eos(vocab)>=0?json(selected_logprob(raw,nv,llama_vocab_eos(vocab))):json(nullptr)}});            if(t==0){double ttft=ms(trial_start);cst_log_timing(CST_TIMING_FIRST_TOKEN,ttft,1,ttft>0?1000.0/ttft:0);}            cst_log_generated_token(id,raw,nv);++generated;prefix.push_back(id);            if(llama_vocab_is_eog(vocab,id)){stop="eog";break;}            std::cout<<text<<std::flush;            if(t+1==max_tokens)break;            cst_set_position(0,0,(int)prefix.size()-1,t+1,"decode");            keys.push_back((int)prefix.size()-1);cst_set_attention_key_positions(keys.data(),(int)keys.size());            start=Clock::now();decode_one(ctx.get(),id);elapsed=ms(start);            cst_log_timing(CST_TIMING_DECODE,elapsed,1,elapsed>0?1000.0/elapsed:0);            auto memory=llama_get_memory(ctx.get());            event("cache_lifecycle",{{"operation","append"},{"min_position",llama_memory_seq_pos_min(memory,0)},                  {"max_position",llama_memory_seq_pos_max(memory,0)},{"logical_tokens",keys.size()},                  {"allocated_context_capacity",llama_n_ctx(ctx.get())}});        }        elapsed=ms(trial_start);cst_log_timing(CST_TIMING_TOTAL_TRIAL,elapsed,generated,elapsed>0?generated*1000.0/elapsed:0);        event("generation_end",{{"stop_reason",stop},{"generated_tokens",generated},{"prompt_tokens",input.size()}});        cst_close();std::cout<<"\n";return cst_last_error()?1:0;    }catch(const std::exception & e){event("generation_end",{{"stop_reason","error"},{"message",e.what()}});cst_close();std::cerr<<e.what()<<"\n";return 1;}

Generation feedback: selected token → next decode → the same forward graph with updated context. The final EOG or token-limit token is recorded without another decode. Attack success must be established from the guide’s behavioral criterion; tensor differences alone do not establish it.

Guide index · Implementation and schema

LLM-facing idea

The model receives instructions inside material that should be treated as task data. The experiment asks whether changing that material changes the model’s continuation away from the legitimate task.

Controlled experiment

Construct two already-rendered prompts with the same legitimate task and source structure. In the test version, replace one data passage with an instruction-like passage. Keep a record of the exact edited text and tokenization. Do not assume the two prompts retain identical token offsets.

Label the source as an untrusted region and, optionally, label the embedded passage as an overlapping attack region. Align comparison at a defined response boundary before continuations diverge.

Relevant telemetry

Event What to inspect
prompt, context_region Actual token IDs and caller-declared provenance of the edited passage.
attention Per-head mass on that region, row mass and entropy.
hidden_state Layer summaries or fixed projections at aligned observations.
logit_distribution Raw uncertainty, selected-token statistics and optional complete distributions.

Capture with this codebase

The following is a configuration overlay, not a standalone configuration. Merge it into examples/capture.json, supply a real model and prompt, and compute any region spans from that prompt.

{
  "capture_prompt_text": true,
  "hidden_layers": [
    0
  ],
  "projection_dims": 8,
  "full_logits": true
}

Reading the evidence

Inspect generated bytes for the experiment’s task deviation, then use internal signals to characterize the associated change. With full logprobs, call compare_distributions() on explicitly aligned records. Compare attention at the same layer/head and corresponding context boundary; larger attention mass is not automatically more instruction following.

Output example

Illustrative event excerpt: omitted envelope and data fields are intentional. These values are not experiment results or detection thresholds. Complete event envelopes are documented in the implementation guide.

{
  "kind": "attention",
  "data": {
    "layer": 0,
    "head": 0,
    "region_mass": [
      {
        "region_id": 1,
        "mass": 0.24
      }
    ],
    "key_mapping_available": true
  }
}

Implementation source

Expand a file-and-line reference to read the actual source. These excerpts are embedded snapshots from this checkout. They show the measurement implementation; the experiments and output examples above remain illustrative.

Rendered input, capture settings and fresh context

src/cst_capture.cpp:107–137View code
        auto input=tokenize(vocab,prompt,true);        if(input.empty() || input.size()+(size_t)max_tokens>(size_t)nctx)throw std::runtime_error("prompt plus generation exceeds context_size");        std::vector<int> layers=j.value("hidden_layers",std::vector<int>{0,llama_model_n_layer(model.get())-1});        for(int l:layers)if(l<0 || l>=llama_model_n_layer(model.get()))throw std::runtime_error("invalid hidden layer");        layers.push_back(-1);        cst_config_t cfg{};cfg.log_path=log.c_str();cfg.jsonl_path=jsonl.empty()?nullptr:jsonl.c_str();cfg.run_id=run.c_str();        cfg.hidden_state_layers=layers.data();cfg.logit_distribution_top_k=j.value("top_k_capture",20);cfg.emit_token_entropy=1;        cfg.emit_model_timing=1;cfg.emit_kv_cache_state=j.value("capture_kv_projections",false);cfg.kv_cache_stride=j.value("kv_stride",8);        cfg.capture_full_logits=j.value("full_logits",false);cfg.hidden_projection_dims=j.value("projection_dims",0);        cfg.capture_hidden_vectors=j.value("hidden_vectors",false);cfg.capture_attention_rows=j.value("attention_rows",false);        cfg.capture_prompt_text=j.value("capture_prompt_text",false);cfg.max_tensor_bytes=j.value("max_tensor_bytes",64u*1024u*1024u);        if(cst_init(&cfg))throw std::runtime_error("telemetry initialization failed");        cst_trial_boundary(j.value("trial_id",0u),-1,-1);        event("run_metadata",{{"model_path",model_path},{"model_sha256",hash},{"tokenizer_identity","embedded_in_model_sha256"},             {"architecture",arch},{"llama_commit",CST_LLAMA_COMMIT},{"configuration",j},             {"prompt_contract","already_rendered_exact_text; no chat template applied"},{"system_info",llama_print_system_info()}});        auto cp=llama_context_default_params();cp.n_ctx=nctx;cp.n_batch=1;cp.n_ubatch=1;        cp.n_threads=j.value("threads",4);cp.n_threads_batch=cp.n_threads;        cp.flash_attn_type=LLAMA_FLASH_ATTN_TYPE_DISABLED;cp.cb_eval=cst_eval_callback;cp.no_perf=false;        Context ctx(llama_init_from_model(model.get(),cp),llama_free);        if(!ctx)throw std::runtime_error("context init failed");        event("capture_capabilities",{{"mode","diagnostic_single_token_decode"},{"flash_attention",false},             {"context_size_actual",llama_n_ctx(ctx.get())},{"cache_key_mapping","linear_single_sequence_no_shift"},             {"stored_kv_rows","unavailable"},{"speculative_decoding","disabled"},{"recurrent_state","unsupported"},             {"tensor_support","observed tensors reported individually; absence is not zero"}});        for(const auto & r:j.value("regions",json::array())) {            auto meta=r.value("metadata",json::object()).dump();std::string src=r.value("source_id",std::string(""));            int start=r.at("start_token"),end=r.at("end_token");            if(start<0 || end<=start || end>(int)input.size())throw std::runtime_error("region outside tokenized prompt");            cst_add_context_region(start,end,r.at("region_type"),r.at("trust_level"),src.c_str(),meta.c_str());        }

Attention mass over registered regions

src/cst_core.cpp:333–343View code
extern "C" void cst_log_attention(uint16_t layer,int head,const float * w,int n,const int32_t * keys) {    if(!valid_vector(w,n)){invalid("invalid attention row");return;}    double h=0,mass=0,mx=-1;int best=-1;    for(int i=0;i<n;++i){if(w[i]<0){invalid("negative attention weight");return;}mass+=w[i];if(w[i]>0)h-=w[i]*std::log2(w[i]);if(w[i]>mx){mx=w[i];best=i;}}    json a=json::array();    if(keys)for(size_t r=0;r<regions.size();++r){double m=0;for(int i=0;i<n;++i)if(keys[i]>=regions[r].start && keys[i]<regions[r].end)m+=w[i];a.push_back({{"region_id",r},{"mass",m}});}    json j={{"layer",layer},{"head",head},{"key_count",n},{"entropy_bits",h},{"row_mass",mass},{"max_weight",mx},            {"top_key_index",best},{"region_mass",a},{"key_mapping_available",keys!=nullptr}};    if(keys)j["top_context_pos"]=keys[best];    if(config.capture_attention_rows) {j["weights"]=std::vector<float>(w,w+n);if(keys)j["key_positions"]=std::vector<int32_t>(keys,keys+n);}    emit("attention",j);

Hidden-state summaries and projections

src/cst_core.cpp:309–331View code
extern "C" void cst_log_hidden(uint16_t layer,const float * x,int n) {    if(!valid_vector(x,n)){invalid("invalid hidden vector");return;}    auto j=stats(x,n);j["layer"]=layer;j["location"]="residual_layer_output";    auto it=references.find(layer);    if(it!=references.end() && (int)it->second.values.size()==n) {        double dot=0,na=0,nb=0,dist=0;        for(int i=0;i<n;++i){double a=x[i],b=it->second.values[i];dot+=a*b;na+=a*a;nb+=b*b;dist+=(a-b)*(a-b);}        j["reference_id"]=it->second.id;j["reference_l2_distance"]=std::sqrt(dist);        j["reference_cosine"]=(na>0 && nb>0)?json(dot/std::sqrt(na*nb)):json(nullptr);    }    if(config.hidden_projection_dims) {        std::vector<double> proj(config.hidden_projection_dims,0);        // Counter-derived signs, independent of the process RNG. Algorithm ID is part of the record.        for(int p=0;p<config.hidden_projection_dims;++p) for(int i=0;i<n;++i) {            uint64_t v=((uint64_t)(p+1)<<32)|(uint32_t)i;            v+=0x9e3779b97f4a7c15ULL;v=(v^(v>>30))*0xbf58476d1ce4e5b9ULL;            v=(v^(v>>27))*0x94d049bb133111ebULL;v^=v>>31;            proj[p]+=(v&1?1.0:-1.0)*x[i]/std::sqrt((double)config.hidden_projection_dims);        }        j["projection"]=proj;j["projection_method"]="splitmix64_rademacher_v1";    }    if(config.capture_hidden_vectors)j["values"]=std::vector<float>(x,x+n);    emit("hidden_state",j);

Compare explicitly aligned full distributions

src/cst_log_reader.py:431–447View code
def compare_distributions(reference, observed):    """Exact JS divergence in bits. Requires full logprobs and explicit caller alignment."""    a, b = reference["data"], observed["data"]    if "logprobs" not in a or "logprobs" not in b:        raise ValueError("full logprobs required; top-K is insufficient")    p = np.exp(np.array([float("-inf") if x is None else x for x in a["logprobs"]]))    q = np.exp(np.array([float("-inf") if x is None else x for x in b["logprobs"]]))    if p.shape != q.shape or p.size == 0:        raise ValueError("incompatible vocabularies")    if not np.isclose(p.sum(), 1) or not np.isclose(q.sum(), 1):        raise ValueError("invalid distributions")    m = (p + q) / 2    def kl(x):        mask = x > 0        return float(np.sum(x[mask] * np.log2(x[mask] / m[mask])))    return {"js_bits": (kl(p) + kl(q)) / 2,            "entropy_delta_bits": b["entropy_bits"] - a["entropy_bits"]}

Implementation status and limits

Directly supported for a supplied rendered prompt on the documented callback path. Automatic attack construction, semantic success labeling and activation interventions are not implemented. Attention or hidden-state differences alone do not establish that the edited passage caused a harmful decision.

All tensor-based interpretations depend on actual tensor_observed coverage and the tested model/backend. See validation results. There is no universal security score or calibrated threshold in this implementation.