Without identity linking, a cross-cloud pivot attack — where stolen AWS
credentials are reused on GCP — appears as two completely unrelated events
to the downstream graph neural network. This model maps all three to nearby
points so Stage 5's graph can connect them and Stage 6's RGCN can detect
the pivot.
1import torch
2import torch.nn as nn
3import torch.nn.functional as F
4from transformers import AutoTokenizer, AutoModel
5from peft import PeftModel
6from huggingface_hub import hf_hub_download
7
8REPO = "sohomn/stage4-identity-embeddings"
9BASE = "google/flan-t5-base"
10
11tokenizer = AutoTokenizer.from_pretrained(REPO)
12base = AutoModel.from_pretrained(BASE)
13encoder = PeftModel.from_pretrained(base, REPO + "/adapter")
14encoder.eval()
15
16proj = nn.Sequential(
17 nn.Linear(512, 256), nn.ReLU(), nn.LayerNorm(256), nn.Linear(256, 128)
18)
19proj.load_state_dict(torch.load(
20 hf_hub_download(REPO, "proj_head.pt"), map_location="cpu"
21))
22proj.eval()
23
24def embed(identity: str, provider: str) -> list:
25 text = f"identity: {identity} provider: {provider}"
26 inputs = tokenizer(text, return_tensors="pt", max_length=32,
27 truncation=True, padding=True)
28 with torch.no_grad():
29 out = encoder.encoder(**inputs)
30 mask = inputs["attention_mask"].unsqueeze(-1).float()
31 emb = (out.last_hidden_state * mask).sum(1) / mask.sum(1)
32 z = proj(emb)
33 z = F.normalize(z, dim=-1)
34 return z[0].tolist()
35
36print(embed("user_alice", "AWS")) # 128-dim vector
37print(embed("user_alice_az", "Azure")) # should be close to above