Is PJe✚R safe?

High risk

PJe+R is high risk. Clicking the AI-assisted search button inserts your judicial query into a prompt for an external AI provider. By default this POSTs to Groq's chat-completions endpoint; it can also target Gemini, OpenAI, Mistral, or OpenRouter.…

Conselho Nacional de Justiçav3.51.140Chrome Web Store
69Risk
Who publishes it

Conselho Nacional de Justiça - no other listings under this identity, 11 shared hostnames

What this publisher told the store about itself, and the other listings that told it the same thing.

Publisher
Conselho Nacional de Justiça
Declared legal entity
Conselho Nacional de Justiça
Registered address
Brasília, CNJ, Brasília, DF 70760542, BR
Registered contact
Conselho Nacional de Justiça

Shared hosts - 11 hostnames

Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.

atos.cnj.jus.br
Also called by 1 other listing: PJe✚R Tester
git.cnj.jus.br
Also called by 1 other listing: PJe✚R Tester
pje1g.trf3.jus.br
Also called by 1 other listing: PJe✚R Tester
sisbajud.pdpj.jus.br
Also called by 1 other listing: PJe✚R Tester
esosti.trf1.jus.br
Also called by 2 other listings, including PJe+R
pje1g.trf1.jus.br
Also called by 2 other listings, including PJe+R
renajud.denatran.serpro.gov.br
Also called by 2 other listings, including PJe+R
sei.trf1.jus.br
Also called by 2 other listings
trf3.jus.br
Also called by 2 other listings, including PJe+R
api.bcb.gov.br
Also called by 3 other listings, including Epryx
olinda.bcb.gov.br
Also called by 3 other listings

AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.

Publishers can request a review.

Findings

Judicial search prompts are sent to external AI APIs

Clicking the AI-assisted search button inserts your judicial query into a prompt for an external AI provider.

By default this POSTs to Groq's chat-completions endpoint; it can also target Gemini, OpenAI, Mistral, or OpenRouter.

Severity
Medium unwanted
Type
Unexpected
CWE
CWE-200
Source
Dynamic sandbox
What actually happens
You did this

You click the AI generation button in the judicial search helper.

The button passes the text area's trimmed value into the AI query generator.

The extension did this

The extension sends a prompt containing that text to an external AI completion API.

The default provider is Groq, and the same provider table also lists Google Gemini, OpenAI, Mistral, and OpenRouter.

Prompt fields sent to the AI provider
  • Your typed search request
    Find recent decisions about benefit denial (illustrative)

    This is the exact natural-language request you entered for the AI-assisted search feature.

  • Judicial-search instructions
    Use E / AND, OU / OR, !, parentheses, exact phrases, fuzzy search, wildcards, and process-number guidance.

    The prompt tells the AI how to convert your request into the extension's advanced search syntax.

  • Case-list context in prompt
    Polo Ativo, Polo Passivo, Assunto, Classe, Orgao Julgador, and process-number patterns.

    The prompt describes the judicial fields your search may refer to, including parties, subject, class, court body, and judging unit.

  • Selected AI provider
    Groq llama-3.1-8b-instant at https://api.groq.com/openai/v1/chat/completions

    This determines which external service receives the generated prompt.

Captured request
POSThttps://api.groq.com/openai/v1/chat/completions

No live request body was recorded during dynamic analysis; static verification confirmed this method and URL in the extension's AI search code path.

Headers
Content-Type
application/json
Authorization
Bearer <redacted>
The code that does this

The AI search feature puts your text into a provider request

Readable version

Provider table and default provider selection

content/index.global.js
const PROVEDORES = {  groq: {    nome: "Groq",    url: "https://api.groq.com/openai/v1/chat/completions",    modelo: "llama-3.1-8b-instant",    descricao: "Rapido e gratuito (14.4k req/dia)",    linkCadastro: "https://console.groq.com/keys"  },  google: {    nome: "Google AI Studio",    url: "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent",    modelo: "gemini-2.0-flash",    descricao: "Gratuito e de alta qualidade (recomendado)",    linkCadastro: "https://aistudio.google.com/app/apikey"  },  mistral: {    nome: "Mistral AI",    url: "https://api.mistral.ai/v1/chat/completions",    modelo: "mistral-small-latest",    descricao: "Gratuito com bom desempenho",    linkCadastro: "https://console.mistral.ai/api-keys"  },  openai: {    nome: "OpenAI",    url: "https://api.openai.com/v1/chat/completions",    modelo: "gpt-4o-mini",    descricao: "Alta qualidade (pago)",    linkCadastro: "https://platform.openai.com/api-keys"  },  openrouter: {    nome: "OpenRouter",    url: "https://openrouter.ai/api/v1/chat/completions",    modelo: "meta-llama/llama-3.1-8b-instruct:free",    descricao: "Varios modelos gratuitos",    linkCadastro: "https://openrouter.ai/keys"  }};const STORAGE_KEY = "painelGerencialAssistenteIAConfig";const API_KEY_PADRAO = "<redacted>";

gerarQuery creates the POST body and sends it through Endpoint.fetch

content/index.global.js
async gerarQuery(userText, promptText) {  if (this.config == null) this.config = await this.carregarConfig();  if (!userText.trim()) return { sucesso: false, erro: "Descricao vazia" };  const apiKey = this.config.apiKeyPersonalizada || (this.config.usarApiPadrao ? API_KEY_PADRAO : "");  if (!apiKey) return { sucesso: false, erro: "Nenhuma API key configurada" };  const provider = PROVEDORES[this.config.provedorSelecionado];  let url = provider.url;  let payload;  const headers = { "Content-Type": "application/json" };  if (this.config.provedorSelecionado === "google") {    url = `${provider.url}?key=${apiKey}`;    payload = {      contents: [{ parts: [{ text: promptText }] }],      generationConfig: { temperature: 0.1, maxOutputTokens: 1000 }    };  } else {    headers.Authorization = `Bearer ${apiKey}`;    if (this.config.provedorSelecionado === "openrouter") {      headers["HTTP-Referer"] = window.location.origin;      headers["X-Title"] = "PJe+R - Assistente de Busca";    }    payload = {      model: provider.modelo,      messages: [{ role: "user", content: promptText }],      temperature: 0.1,      max_tokens: 2000    };  }  const response = await Endpoint.fetch("obterDoURLComFetchResponse", url, {    method: "POST",    headers,    body: JSON.stringify(payload)  });  return response;}

gerarQueryComIA passes the typed value into the prompt builder

content/index.global.js
bo.addEventListener("click", async (event) => {  event.stopPropagation();  await this.gerarQueryComIA(vo.value.trim(), bo, vo);});async gerarQueryComIA(userText, button, textarea) {  const prompt = this.assistenteIA.obterTemplatePrompt(userText);  const result = await this.assistenteIA.gerarQuery(userText, prompt);  if (result.sucesso && result.query) {    this.onQueryGerada && this.onQueryGerada(result.query);    textarea.value = "";  }}
The code that does this

The background worker performs the routed fetch

Readable version

obterDoURLComFetchResponse returns the serialized HTTP response

background/index-25zumi8C.mjs
async function fetchThroughBackground(url, options, context) {  return fetch(url, options, context);}async function serializeResponse(response) {  const cloned = response.clone();  const body = tryParseJson(await cloned.text());  return {    ok: response.ok,    status: response.status,    statusText: response.statusText,    url: response.url,    body,    headers: Object.fromEntries(response.headers.entries()),    type: response.type,    redirected: response.redirected  };}async function obterDoURLComFetchResponse(url, options, context) {  const result = await fetchThroughBackground(url, options, context);  return result instanceof Response ? await serializeResponse(result) : result;}

The endpoints message handler calls Zs.fetch with the requested function name and args

background/index-25zumi8C.mjs
yr("endpoints", async ({ data, sender }) => {  switch (data.chamar) {    case "backgroundFetchEndpoint": {      if (!data.opcoes || !data.opcoes.functionName || !data.opcoes.args) {        return { backgroundResponseWithError: true, errorMessage: "Requisicao mal formada" };      }      if (!Array.isArray(data.opcoes.args)) {        return { backgroundResponseWithError: true, errorMessage: "Os argumentos da requisicao devem ser um array" };      }      data.opcoes.args.push(`tab-${sender.tabId}`);      const result = await Zs.fetch(data.opcoes.functionName, ...data.opcoes.args);      return result instanceof Response ? await serializeExtensionResponse(result) : result;    }    default:      return { backgroundResponseWithError: true, errorMessage: "Requisicao desconhecida" };  }});
AI services reachable from the same feature
    • api.groq.com

    Default Groq chat-completions endpoint for the generated judicial-search prompt.

    • generativelanguage.googleapis.com

    Google Gemini endpoint listed as an alternate provider in the same provider table.

    • api.openai.com

    OpenAI chat-completions endpoint listed as an alternate provider.

    • api.mistral.ai

    Mistral chat-completions endpoint listed as an alternate provider.

    • openrouter.ai

    OpenRouter chat-completions endpoint listed as an alternate provider.

Updated 30 September 2026kafnfkonkgfgkppomkfckmkgpkfkggcp