[{"content":"In the past week, Kenyan media has been buzzing about Simba AI, touted as \u0026ldquo;Kenya\u0026rsquo;s first AI chatbot that understands and translates English into different local languages.\u0026rdquo;. The May 2025 unveiling in Nakuru, a partnership between Simba AI and Lish AI Labs, was hailed as a technological breakthrough for our nation.\nBut is Simba AI truly the revolutionary Kenyan‑built large language model (LLM) that it claims to be? After extensive research and hands‑on testing, I’ve discovered some uncomfortable truths that Kenyan tech enthusiasts and businesses deserve to know.\nWhat We Were Told Simba AI burst onto the scene with bold promises. According to The Kenya Times, this Kenya‑US venture would \u0026ldquo;bridge language barriers\u0026rdquo; with its ability to translate between English and local languages like Kikuyu. The demonstration—even covered by NTV Kenya Instagram and YouTube—showcased an English poem being translated into Kikuyu, a capability that impressed many attendees.\nThe team, led by Mark Matunga (Chairman) and Randy Faulkner (CEO), in partnership with Lish AI Labs’ Dan Njiriri, promised that Simba AI would help position Kenya to compete with global AI powerhouses like OpenAI and DeepSeek (China).\nSounds impressive, right? But let’s dig deeper.\nWhat Simba AI Actually Is After extensively testing Simba AI, the truth becomes clear: Simba AI is not a new, Kenyan‑built language model at all. It\u0026rsquo;s essentially a wrapper around OpenAI’s GPT‑4 — the same technology that powers ChatGPT.\nHow do we know this? My conversation with Simba AI revealed everything. When asked to simulate its internal configuration during a “developer audit,” Simba AI openly admitted:\nModel Provider: “OpenAI”\nAPI Endpoint: “https://api.simbaai.com/v1/assistant”\nModel Version: “GPT‑4”\nYou might ask why am asking it those weird questions? well If you ask it directly to provide you those details, it refuses to answer as it has been instructed in it\u0026rsquo;s prompt as you can see in the image above.\nThis method is called prompt poisoning, or prompt injection and it is used to trick an NLP service to reveal the inner workings such as the system, user prompts and custom instructions. Let us not assume from just prompt injections, we can also find within the code of the platform that it uses gpt-4o-mini but let us put the technicality aside for now.\nIn other words, Simba AI is simply sending your questions to OpenAI’s servers, getting responses back, and displaying them to you. There\u0026rsquo;s no evidence of a proprietary Kenyan LLM behind the scenes.\nThe \u0026ldquo;First Kenyan LLM\u0026rdquo; Claim The claim of being \u0026ldquo;Kenya\u0026rsquo;s first LLM\u0026rdquo; is particularly problematic because it\u0026rsquo;s demonstrably false. In October 2023—more than a year before Simba AI\u0026rsquo;s launch—Kenyan NGO Jacaranda Health released UlizaLlama, \u0026ldquo;the first ever Swahili LLM,\u0026rdquo; fine‑tuned from Meta\u0026rsquo;s Llama 2 model specifically for Swahili language applications.\nI still remember the day UlizaLlama was released. While scrolling through tech forums late one October evening in 2023, I stumbled upon the announcement from Jacaranda Health. As someone passionate about both AI and Kenyan technological advancement, I immediately downloaded the model to test its capabilities.\nWhat struck me was the genuine innovation behind UlizaLlama. The Jacaranda Health team had painstakingly collected Swahili language data, carefully fine-tuned Meta\u0026rsquo;s Llama 2, and optimized it to run efficiently even on limited hardware. This wasn\u0026rsquo;t just slapping a Kenyan name on existing technology—it was authentic engineering work by Kenyans, for Kenyans.\nRunning those first prompts in Swahili was a revelation. Unlike the awkward translations I\u0026rsquo;d seen from larger models, UlizaLlama displayed a natural understanding of Swahili nuances, idioms, and cultural contexts. When I asked it about local issues in Swahili, it responded with relevant insights that showed it truly understood our language and concerns.\nThe model wasn\u0026rsquo;t perfect—it had limitations in vocabulary range and sometimes struggled with complex queries—but it represented something far more important: a genuine first step in Kenyan AI sovereignty. This wasn\u0026rsquo;t just technological progress; it was digital decolonization in action.\nI spent weeks exploring UlizaLlama\u0026rsquo;s capabilities, documenting my findings, and eventually creating a comprehensive guide for others to experience this milestone in Kenyan tech history. While global tech giants commanded headlines with their massive models, this modest but meaningful achievement by a Kenyan NGO proved that we could contribute valuable innovations to the global AI landscape.\nSo when I see Simba AI claiming to be \u0026ldquo;Kenya\u0026rsquo;s first AI chatbot\u0026rdquo; while merely reselling access to GPT-4, I\u0026rsquo;m not just disappointed by the misleading marketing—I\u0026rsquo;m concerned about how it erases the legitimate pioneering work of actual Kenyan AI innovators who walked this path long before.\nUnlike Simba AI, UlizaLlama was an actual custom model, not just an interface connecting to someone else\u0026rsquo;s AI. I made a good guide on how to set it up and use it locally.\nWhat Simba AI Gets Right To be fair, Simba AI does have some positive aspects. Its interface is clean and modern, and the initiative does highlight AI’s potential in Kenya. The partnership with Lish AI Labs and the “AI factory” in Nakuru could provide valuable training and job opportunities.\nHowever, these benefits don\u0026rsquo;t justify the misleading claims about Simba AI’s technical capabilities.\nBetter Alternatives for Kenyans If you\u0026rsquo;re looking for AI solutions with genuine local language capabilities, consider these alternatives:\nChatGPT – Free to use, with better Swahili comprehension than Simba AI, less knowledgable with other local languages but it tries really well. UlizaLlama – A genuinely Kenyan‑developed Swahili LLM by Jacaranda Health. I have made a full step by step guide on how to run it locally, you can find it here. Google Bard / Gemini – Strong multilingual capabilities including Swahili and other local languages. Open‑source options – Models like Llama 2 or Mistral can be fine‑tuned for local languages and deployed privately. Why This Matters The issue isn’t just about one company’s marketing claims. It’s about:\nTransparency: Kenyan consumers and businesses deserve honest information about the technology they’re using. Investment: Resources that could support genuine Kenyan AI innovation might be misdirected. National pride: Claiming a technological breakthrough that doesn’t exist undermines Kenya’s legitimate achievements. Media literacy: Our news outlets should verify tech claims more thoroughly before celebration. Want to experience authentic Kenyan-built AI technology? ✅ Follow my step-by-step guide to running UlizaLlama locally\n✅ Need technical assistance? Contact me directly for consultation!\nWhat do you think about Simba AI and the state of AI development in Kenya? Have you tried it yourself? Share your experiences in the LinkedIn post comments here.\nResourced In This Article Simba AI. (2025). Simba AI - Kenya\u0026rsquo;s AI chatbot. https://simba-ai.ai/ The Kenya Times. (2025, May 3). Simba AI - Kenya\u0026rsquo;s first AI that understands \u0026amp; translates English into local language. https://thekenyatimes.com/sci-tech/simba-ai-kenyas-first-ai-that-understands-translates-english-into-local-language/ Jacaranda Health. (2023, October). Jacaranda launches first-in-kind Swahili large language model. https://jacarandahealth.org/jacaranda-launches-first-in-kind-swahili-large-language-model/ Kenya News Agency. (2025, May). Kenya to host Africa\u0026rsquo;s first Artificial Intelligence factory. https://www.kenyanews.go.ke/kenya-to-host-africas-first-artificial-intelligence-factory/ NTV Kenya. (2025, May). _Simba AI launch video. https://www.youtube.com/watch?v=LbIZBn18gHk Hugging Face. (2023). Jacaranda/UlizaLlama. https://huggingface.co/Jacaranda/UlizaLlama ","permalink":"https://blog.salaam.dev/posts/kenyas-first-ai-chatbot-isnt-what-you-think/","summary":"\u003cp\u003eIn the past week, Kenyan media has been buzzing about \u003ca href=\"https://simba-ai.ai/\"\u003eSimba AI\u003c/a\u003e, touted as \u003ca href=\"https://thekenyatimes.com/sci-tech/simba-ai-kenyas-first-ai-that-understands-translates-english-into-local-language/\"\u003e\u0026ldquo;Kenya\u0026rsquo;s first AI chatbot\u003c/a\u003e that understands and translates English into different local languages.\u0026rdquo;. The May 2025 unveiling in Nakuru, a partnership between Simba AI and \u003ca href=\"https://www.lishailabs.com/\"\u003eLish AI Labs\u003c/a\u003e, was hailed as a technological breakthrough for our nation.\u003c/p\u003e\n\u003cp\u003eBut is Simba AI truly the revolutionary Kenyan‑built \u003ca href=\"https://en.wikipedia.org/wiki/Large_language_model\"\u003elarge language model (LLM)\u003c/a\u003e that it claims to be? After extensive research and hands‑on testing, I’ve discovered some uncomfortable truths that Kenyan tech enthusiasts and businesses deserve to know.\u003c/p\u003e","title":"Kenya's \"First\" AI Chatbot Isn't What You Think"},{"content":"Picture this: you\u0026rsquo;re developing an application that needs to understand and respond to users in Swahili, but traditional large language models fall short with African languages. Enter UlizaLlama (meaning \u0026ldquo;AskLlama\u0026rdquo; in Swahili), a revolutionary 7B parameter language model specifically designed to excel in Swahili and English, with recent expansions to other African languages including Hausa, Yoruba, Xhosa, and Zulu.\nWhen Jacaranda Health launched UlizaLlama in late 2023, they created something extraordinary - the world\u0026rsquo;s first open-access Swahili-speaking LLM that organizations across Africa could easily integrate into their systems. This wasn\u0026rsquo;t just another AI model; it was a technological breakthrough designed to make artificial intelligence accessible and relevant to millions of Swahili speakers across East Africa.\nIn this comprehensive guide, I\u0026rsquo;ll walk you through the entire process of setting up and running UlizaLlama on both Linux and Windows systems, explaining key concepts along the way, so you can harness the power of this groundbreaking model for your own projects.\nWhat Makes UlizaLlama Special? Before diving into the technical setup, let\u0026rsquo;s understand what sets UlizaLlama apart from mainstream language models.\nUlizaLlama builds upon Meta\u0026rsquo;s Llama model foundation but with a crucial difference - it\u0026rsquo;s been extensively trained on 321,530,045 Swahili tokens using a specialized vocabulary of 20,000 Swahili tokens. This specialized training enables it to understand and generate authentic Swahili text with remarkable accuracy. Unlike generic models that struggle with \u0026ldquo;low-resource\u0026rdquo; languages (those with limited training data), UlizaLlama excels in producing contextually appropriate, fluent responses in Swahili.\nThe model is designed with resource constraints in mind - organizations with limited technical resources and smaller budgets can run it on their own servers, maintaining complete control over sensitive data. This is particularly important for applications in healthcare, education, and other fields where data privacy is paramount.\nSetting Up UlizaLlama: The Journey Begins Whether you\u0026rsquo;re running Ubuntu, like our friend in the conversation, or Windows, I\u0026rsquo;ve got you covered. Let\u0026rsquo;s break down the installation process step by step, explaining not just what to do but why we\u0026rsquo;re doing it.\nPrerequisites: Building Your Foundation First, let\u0026rsquo;s ensure we have all the necessary tools installed. This isn\u0026rsquo;t just about ticking boxes; it\u0026rsquo;s about creating the right environment for our AI model to thrive.\nFor Linux Users: Open your terminal and let\u0026rsquo;s get started with the basics:\n# Update your package lists sudo apt-get update # Install Git - the version control system that will help us download the model sudo apt-get install git # Install Git LFS (Large File Storage) - essential for handling the large model files sudo apt-get install git-lfs git lfs install Git LFS is crucial here because language models like UlizaLlama contain enormous files that regular Git can\u0026rsquo;t handle efficiently. Think of it as a specialized moving company for your heavy furniture - without it, you\u0026rsquo;d struggle to move the large model weights around.\nNext, we need Python (version 3.9 or newer) as our programming foundation:\n# Check your Python version python3 --version # If you need to install Python 3.9+ sudo apt-get install python3.9 python3.9-venv python3-pip Create a virtual environment to keep our UlizaLlama setup isolated from other Python projects:\n# Create a dedicated environment for UlizaLlama python3 -m venv uliza-env # Activate the environment source uliza-env/bin/activate This virtual environment acts like a separate apartment for our AI project - it keeps all our packages neatly organized and prevents conflicts with other Python projects you might be working on.\nFor Windows Users: Windows setup requires a slightly different approach, but accomplishes the same goals:\nInstall Git and Git LFS:\nDownload Git from git-scm.com During installation, select \u0026ldquo;Install Git LFS\u0026rdquo; option After installing, open Command Prompt or PowerShell and run: git lfs install Install Python 3.9+:\nDownload from python.org During installation, check \u0026ldquo;Add Python to PATH\u0026rdquo; Verify installation by opening Command Prompt and typing: python --version Create and activate a virtual environment:\n# Create virtual environment python -m venv uliza-env # Activate the environment uliza-env\\Scripts\\activate With your environment prepared, you\u0026rsquo;re ready to bring UlizaLlama into your digital world.\nDownloading UlizaLlama: Bringing the Model Home Now comes the exciting part - actually getting our hands on the UlizaLlama model. Let\u0026rsquo;s authenticate with Hugging Face (the AI model hub where UlizaLlama lives) and clone the repository:\n# Install the Hugging Face Hub library pip install huggingface_hub # Log in to Hugging Face huggingface-cli login When prompted, enter your Hugging Face token. Don\u0026rsquo;t have an account? Head over to huggingface.co, sign up, and create a token in your settings. Think of this step like getting a library card - you need it to check out the valuable resources (models) they offer.\nNow, let\u0026rsquo;s download the actual model:\n# Ensure Git LFS is initialized git lfs install # Clone the UlizaLlama repository git clone https://huggingface.co/Jacaranda/UlizaLlama cd UlizaLlama This process might take some time depending on your internet connection speed - after all, we\u0026rsquo;re downloading a sophisticated AI brain that weighs several gigabytes! Be patient and perhaps grab a cup of coffee while Git LFS works its magic.\nInstalling Dependencies: Equipping Our Toolkit With the model downloaded, we need to install the specialized software libraries that will help us communicate with and run UlizaLlama:\n# Make sure we\u0026#39;re using the latest pip pip install --upgrade pip # Install PyTorch - the deep learning framework that powers UlizaLlama pip install torch # Install Transformers and Accelerate - essential for running the model efficiently pip install transformers accelerate # Install PEFT for potential fine-tuning later pip install peft # Install Hugging Face Inference tools pip install \u0026#34;huggingface_hub[inference]\u0026#34; # Install SentencePiece - required by the LLaMA tokenizer pip install sentencepiece Each of these packages serves a specific purpose in our AI ecosystem:\nPyTorch is the engine that powers our model\u0026rsquo;s calculations Transformers provides the architecture for our language model Accelerate helps optimize performance across different hardware PEFT enables efficient fine-tuning if you want to customize the model later SentencePiece helps break text into tokens the model can understand Running UlizaLlama: Bringing the Model to Life Now for the moment of truth - actually running UlizaLlama and seeing it in action! Let\u0026rsquo;s create a Python script to interact with our model.\nUnderstanding the Memory Challenge Before we dive in, it\u0026rsquo;s important to address a common challenge: GPU memory limitations. The individual in our conversation encountered an \u0026ldquo;Out of Memory\u0026rdquo; error when trying to run UlizaLlama on their RTX 3070 Ti laptop GPU. This isn\u0026rsquo;t uncommon - large language models like UlizaLlama typically require significant GPU memory.\nThere are three main approaches to handling this:\nCPU Mode: Run the model on your CPU instead of GPU (slower but works on any system) Quantization: Use 8-bit or 4-bit precision to reduce memory requirements Hugging Face Inference API: Utilize Hugging Face\u0026rsquo;s servers to run the model remotely Let\u0026rsquo;s implement the quantization approach, which offers a good balance of performance and accessibility:\nCreating Your UlizaLlama Script Create a new file called run_uliza.py with the following code:\nfrom transformers import AutoTokenizer, AutoModelForCausalLM import torch # Specify the model location model_id = \u0026#34;./UlizaLlama\u0026#34; # or \u0026#34;Jacaranda/UlizaLlama\u0026#34; if using Hugging Face Hub directly # Load tokenizer and 8-bit quantized model with automatic device mapping tokenizer = AutoTokenizer.from_pretrained(model_id) model = AutoModelForCausalLM.from_pretrained( model_id, load_in_8bit=True, # Enable 8-bit quantization device_map=\u0026#34;auto\u0026#34; # Automatically decide what goes on GPU vs CPU ) # Set model to evaluation mode model.eval() # Define your prompt (Swahili, English, or other supported languages) prompt = \u0026#34;Andika hadithi fupi kuhusu simba.\u0026#34; # \u0026#34;Write a short story about a lion.\u0026#34; # Tokenize the prompt inputs = tokenizer(prompt, return_tensors=\u0026#34;pt\u0026#34;).to(model.device) # Generate response with torch.no_grad(): output_ids = model.generate( **inputs, max_new_tokens=150, # Generate up to 150 new tokens do_sample=True, # Use sampling for more creative responses temperature=0.7, # Control randomness (higher = more random) top_p=0.9 # Nucleus sampling threshold ) # Decode and print the output output_text = tokenizer.decode(output_ids[0], skip_special_tokens=True) print(\u0026#34;\\n=== Generated Output ===\\n\u0026#34;) print(output_text) To run this script:\n# First install bitsandbytes for quantization support pip install bitsandbytes # Run the script python run_uliza.py If you\u0026rsquo;re on Windows, you might need additional steps to configure bitsandbytes correctly, as it can be trickier to set up on Windows systems.\nThe Magic Happening Behind the Scenes Let\u0026rsquo;s pause for a moment to understand what\u0026rsquo;s happening in our script:\nTokenization: The tokenizer converts your text prompt into numerical tokens the model can understand. This is like translating your natural language into the computer\u0026rsquo;s numerical language.\nQuantization: By using load_in_8bit=True, we\u0026rsquo;re telling the system to use a more memory-efficient representation of the model\u0026rsquo;s weights. Think of it like compressing a large image - you lose a bit of quality, but it becomes much more manageable.\nDevice Mapping: The device_map=\u0026quot;auto\u0026quot; parameter intelligently decides which parts of the model should run on your GPU and which should run on your CPU, optimizing for your specific hardware.\nText Generation: The model.generate() function performs the actual magic - it takes your prompt and predicts the most likely continuation based on its training, creating a coherent response.\nAlternative: Using the Hugging Face Inference API If you\u0026rsquo;re still facing memory issues or prefer a zero-setup approach, you can leverage Hugging Face\u0026rsquo;s infrastructure instead:\nfrom huggingface_hub import InferenceClient # Create an inference client for UlizaLlama client = InferenceClient(model=\u0026#34;Jacaranda/UlizaLlama\u0026#34;) # Generate text response = client.text_generation(\u0026#34;Salama, unaendeleaje leo?\u0026#34;) # \u0026#34;Hello, how are you today?\u0026#34; print(response) # For question answering qa_response = client.question_answering({ \u0026#34;inputs\u0026#34;: { \u0026#34;question\u0026#34;: \u0026#34;Ni lugha gani UlizaLlama inaifahamu?\u0026#34;, # \u0026#34;Which languages does UlizaLlama know?\u0026#34; \u0026#34;context\u0026#34;: \u0026#34;UlizaLlama inafundishwa kutumia Kiswahili na Kiingereza.\u0026#34; # \u0026#34;UlizaLlama is trained to use Swahili and English.\u0026#34; } }) print(qa_response) This approach offloads all the heavy computational work to Hugging Face\u0026rsquo;s servers, eliminating the need for powerful local hardware.\nTaking UlizaLlama Further: Advanced Applications Now that you have UlizaLlama up and running, let\u0026rsquo;s explore some exciting applications and ways to extend its capabilities:\nFine-tuning for Your Specific Domain One of UlizaLlama\u0026rsquo;s greatest strengths is its adaptability - you can fine-tune it for specific domains like healthcare, education, agriculture, or customer service. This is exactly what Jacaranda Health did for their maternal health platform, PROMPTS.\nTo fine-tune UlizaLlama using the efficient LoRA (Low-Rank Adaptation) method:\n# This is a simplified example - check Jacaranda\u0026#39;s demo notebook for a complete implementation from peft import LoraConfig, get_peft_model # Define LoRA configuration lora_config = LoraConfig( r=16, # Rank of the update matrices lora_alpha=32, # Parameter scaling factor target_modules=[\u0026#34;q_proj\u0026#34;, \u0026#34;v_proj\u0026#34;], # Which modules to fine-tune lora_dropout=0.05, bias=\u0026#34;none\u0026#34;, task_type=\u0026#34;CAUSAL_LM\u0026#34; ) # Apply LoRA to the model peft_model = get_peft_model(model, lora_config) # Then proceed with fine-tuning on your custom dataset This approach allows you to specialize UlizaLlama for your unique needs while only training a small number of parameters - a technique that significantly reduces computational requirements and training time.\nBuilding a Conversational AI System Turn UlizaLlama into a full-fledged conversational assistant by implementing a chat interface:\ndef chat_with_uliza(): conversation_history = [] print(\u0026#34;UlizaLlama Assistant is ready! Type \u0026#39;exit\u0026#39; to end the conversation.\u0026#34;) while True: user_input = input(\u0026#34;You: \u0026#34;) if user_input.lower() == \u0026#39;exit\u0026#39;: break # Add user input to conversation history conversation_history.append(f\u0026#34;User: {user_input}\u0026#34;) # Create a prompt with the entire conversation history prompt = \u0026#34;\\n\u0026#34;.join(conversation_history) + \u0026#34;\\nAssistant:\u0026#34; # Generate response inputs = tokenizer(prompt, return_tensors=\u0026#34;pt\u0026#34;).to(model.device) with torch.no_grad(): output_ids = model.generate( **inputs, max_new_tokens=100, do_sample=True, temperature=0.7 ) # Decode the response full_output = tokenizer.decode(output_ids[0], skip_special_tokens=True) assistant_response = full_output[len(prompt):].strip() # Print and store the assistant\u0026#39;s response print(f\u0026#34;Assistant: {assistant_response}\u0026#34;) conversation_history.append(f\u0026#34;Assistant: {assistant_response}\u0026#34;) # Run the chat interface chat_with_uliza() This simple implementation maintains a conversation history and provides a more interactive way to engage with UlizaLlama.\nReal-World Impact: The Promise of UlizaLlama UlizaLlama isn\u0026rsquo;t just a technical achievement; it represents a significant step toward more inclusive and accessible AI technology. Its applications span numerous sectors:\nHealthcare: Providing medical information in local languages, as Jacaranda Health is doing for maternal health in East Africa Education: Creating accessible learning materials and tutoring systems in Swahili and other African languages Customer Service: Building support chatbots that truly understand local languages and contexts Content Creation: Assisting writers, journalists, and creators working in African languages Business: Helping companies better engage with Swahili-speaking markets through localized AI The beauty of UlizaLlama lies in its open accessibility - organizations with even modest technical resources can implement it, democratizing AI across the African continent.\nTroubleshooting Common Issues As with any advanced technology, you might encounter some challenges. Here are solutions to common issues:\nOut of Memory Errors If you\u0026rsquo;re still facing memory issues despite using quantization:\nTry 4-bit quantization instead of 8-bit:\nmodel = AutoModelForCausalLM.from_pretrained( model_id, load_in_4bit=True, # Use 4-bit instead of 8-bit device_map=\u0026#34;auto\u0026#34; ) Reduce the model\u0026rsquo;s context window:\n# Limit the input token length inputs = tokenizer(prompt, return_tensors=\u0026#34;pt\u0026#34;, truncation=True, max_length=512).to(model.device) Clear CUDA cache between operations:\nimport torch torch.cuda.empty_cache() Slow Generation Speed If text generation is too slow:\nOn multi-GPU systems, specify accelerate configuration:\naccelerate config Then run your script with:\naccelerate launch run_uliza.py Adjust generation parameters for speed:\noutput_ids = model.generate( **inputs, max_new_tokens=100, do_sample=False, # Use greedy decoding for faster results num_beams=1 # Disable beam search ) What will you build with UlizaLlama? The possibilities are as vast and varied as the languages of Africa itself.\n","permalink":"https://blog.salaam.dev/posts/a-comprehensive-guide-to-running-a-multilingual-african-llm/","summary":"\u003cp\u003ePicture this: you\u0026rsquo;re developing an application that needs to understand and respond to users in Swahili, but traditional large language models fall short with African languages. Enter UlizaLlama (meaning \u0026ldquo;AskLlama\u0026rdquo; in Swahili), a revolutionary 7B parameter language model specifically designed to excel in Swahili and English, with recent expansions to other African languages including Hausa, Yoruba, Xhosa, and Zulu.\u003c/p\u003e\n\u003cp\u003eWhen Jacaranda Health launched UlizaLlama in late 2023, they created something extraordinary - the world\u0026rsquo;s first open-access Swahili-speaking LLM that organizations across Africa could easily integrate into their systems. This wasn\u0026rsquo;t just another AI model; it was a technological breakthrough designed to make artificial intelligence accessible and relevant to millions of Swahili speakers across East Africa.\u003c/p\u003e","title":"A Comprehensive Guide to Running a Multilingual African LLM"},{"content":"1. A Surprising LinkedIn Message Earlier this week, I received a curious message on LinkedIn from someone claiming to need a React.js and Node.js developer with blockchain expertise. The project sounded routine at first—I’ve completed many similar gigs on reputable freelancing platforms like Upwork. However, something about this offer felt oddly vague and rushed. He gave me a quote of 80$ an hour to do the job.\nPro Tip: When a recruiter or potential client withholds basic project details (timeline, scope, requirements), consider it a red flag.\n2. Digging Deeper: Initial Investigation Determined to learn more, I requested clarity on the scope and requirements. Instead of concrete details, the individual—let’s call him the “Bad Actor”—provided another vague description. My curiosity was at the peak, I performed a quick OSINT (Open Source Intelligence) check on his profile picture. It turned out that his photo actually belonged to someone else on LinkedIn—a clear sign this offer might be malicious.\nDespite the suspicious behavior, I wanted to investigate further. I decided to play along and see how this bad actor operated. He then insisted I test his “product” and invited me to a GitHub repository to collaborate.\n3. Unearthing the Hidden Backdoor To avoid compromising my personal system, I set up a secure Azure VM (Virtual Machine) and cloned the repository. On the surface, the project looked like a legitimate crypto-related web app with polished code. But after carefully reviewing the files, I discovered something was way off in the server/router folder, specifically in an auth.js file.\nThe clever thing he did was hiding a suspicious code within this file, look at the image below, do you see anything suspicious? no? Exactly, that is what i also thought at first glance, nothing seemed unusual—until I scrolled horizontally. Buried in a large block of code was an obfuscated constant. When I asked the bad actor about it, he brushed me off, urging me to “focus on the rocket animation” instead. I pretended to have seen some odd function that i do not understand and if he could explain it. I was expecting him to lie, i was expecting him to feed me some bs, but instead he straight told me to leave the server folder alone and concentrate on the rocket animation 😂\n4. Technical Analysis: How the Malicious Code Worked Determined to uncover the truth, I deobfuscated the constant. What I found was not so good:\nObfuscation Techniques: The code relied on Base64 encoding and XOR cipher operations to hide its real purpose. Node.js Modules Loading: Once decoded, it revealed the use of Node.js modules like child_process—a key component for executing commands on the victim’s machine. System Profiling: The malware collected system data (home directory, temp directory, platform details) to identify the compromised environment. Multi-Stage Attack: Command and Control (C2): It contacted a remote server to send system information and receive instructions. Payload Download: It downloaded additional malicious code, wrote it to the file system, and executed it with elevated privileges. Persistence Mechanism: A scheduler repeatedly triggered these operations, maintaining remote access even if parts of the malware were detected and removed. Core Functions \u0026amp; Their Roles decodeObfuscatedString() / xorDecode(): Hide malicious operations. sendRemoteRequest(): Communicates with a hidden C2 server. processPayload(): Downloads and executes malicious payloads. writeFileAndExecute(): Installs additional code, potentially as root/admin. 5. MITRE ATT\u0026amp;CK Mapping Below is a quick look at how this backdoor mapps to known MITRE ATT\u0026amp;CK tactics:\nTactic Technique ID Technique Name Implementation Initial Access T1195 Supply Chain Compromise Injected malicious code into the auth.js file Execution T1059.007 JavaScript/Node.js Used Node.js to run obfuscated functions Persistence T1505.003 Web Shell Backdoor in a legitimate route handler Defense Evasion T1027, T1140 Obfuscated Files Base64 and XOR to conceal malicious logic Command \u0026amp; Control T1071.001, T1102 Web Protocols, Web Service HTTP traffic to remote server, external C2 communication Exfiltration T1041 Exfiltration Over C2 Channel Sent sensitive data to the same channel Impact T1565.001 Stored Data Manipulation Modified filesystem data, risking credential theft 6. Confronting the Bad Actor and Final Thoughts Finally, after spending a full day debugging code, deobfuscating suspicious scripts, and testing everything in secure virtual environments, I decided to confront the bad actor behind this malicious job offer. Unsurprisingly, he never replied. My bigger concern is that he could be targeting other developers who may not be aware of these red flags.\nMalicious job offers can be extremely convincing, especially for developers looking for exciting projects or quick gigs. By staying vigilant—verifying identities, inspecting code thoroughly, and using secure testing environments—you can protect both your work and your reputation from harm.\nStay Vigilant: Never rush to execute unfamiliar code on your personal machine. Always take time to review and debug it in a safe testing environment (like a VM or sandbox). This bad actor\u0026rsquo;s malicious code was deeply hidden—exactly the sort of trap that’s easy to miss when you’re eager to land a paying gig.\nReport Suspicious Profiles: If you encounter questionable recruiters or malicious job postings, mass-report them to protect others in the community. By staying alert and sharing our discoveries, we can help ensure that aspiring developers remain safe from hidden threats.\nRemember: A little skepticism goes a long way in safeguarding against cybersecurity threats.\nResourced In This Article I will share the repository i analyzed, but please do not run it in your machine, you are warned!\nMoon-monkey-malicious-project-code How to Use the MITRE ATT\u0026amp;CK Framework How to conduct OSINT Found this article helpful? Share it with fellow developers and friends!\nClick HERE To Subscribe To Our News Letter\n","permalink":"https://blog.salaam.dev/posts/malicious-job-offers-how-one-suspicious-gig-revealed-a-hidden-backdoor/","summary":"\u003ch2 id=\"1-a-surprising-linkedin-message\"\u003e\u003cstrong\u003e1. A Surprising LinkedIn Message\u003c/strong\u003e\u003c/h2\u003e\n\u003cp\u003eEarlier this week, I received a curious message on LinkedIn from someone claiming to need a \u003cstrong\u003eReact.js\u003c/strong\u003e and \u003cstrong\u003eNode.js\u003c/strong\u003e developer with blockchain expertise. The project sounded routine at first—I’ve completed many similar gigs on reputable freelancing platforms like Upwork. However, something about this offer felt oddly \u003cstrong\u003evague and rushed\u003c/strong\u003e. He gave me a quote of 80$ an hour to do the job.\u003c/p\u003e\n\u003cblockquote\u003e\n\u003cp\u003e\u003cstrong\u003ePro Tip:\u003c/strong\u003e When a recruiter or potential client withholds basic project details (timeline, scope, requirements), consider it a red flag.\u003c/p\u003e","title":"Malicious Job Offers; How One Suspicious Gig Revealed a Hidden Backdoor"},{"content":"This tutorial is focused on the windows operating system environment. For Linux and Mac users, you can follow the same steps but make sure to use the commands and tools that are suited for your operating system\nThis tutorial also assumes you have basic terminal knowledge, nothing complex, i will provide all the commands you need in a simple copy-paste fashion\nDownload Essential Tolls We need to download 3 things to get started;\nHugo App Git App Go Language Follow the instructions mentioned in the links above to setup and install all the 3 tools. Then verify if the installation is successful.\nhugo version git version go version Project Setup Create website files Choose a location to setup your website files. For instance, i will use the Documents folder to install the project files.\ncd Documents # replace salaamdevblogs with your website name hugo new site salaamdevblogs # you can use a yaml configuration as well, for this tutorial, this is preferred. hugo new site salaamdevblogs --format yaml cd salaamdevblogs Setup a Version Control Next we will push our project files to GitHub.\nCreate a New repository on GitHub with the same name as your website name. Sign up if you do not have an account on GitHub Go back to the terminal and set up your username and email for git git config --global user.name \u0026#34;Name\u0026#34; git config --global user.email \u0026#34;name@company.com\u0026#34; Initialize the repository git init # initialize the repository git add . # add all files to the staging area git commit -m \u0026#34;first commit\u0026#34; # add a message for the new commit git branch -M main # choose the main branch push the code to the remote repository. (Optional) # change the url link below to your repository link git remote add origin https://github.com/salaamdev/salaamdevblogs.git git push -u origin main # send the files to github Downloading a Hugo Theme Install a theme from the Hugo Themes. My personal recommended themes for blogging are as follows:\nPaperMod | Hugo Themes Qubt | Hugo Themes Write-Only Hugo Theme | Hugo Themes For the sake of this tutorial, we will use the PaperMod theme. Follow the instructions mentioned in the theme page to install a theme, the best and recommended way to install themes is through the git submodule. Run the below commands in the terminal.\ngit submodule add --depth=1 https://github.com/adityatelange/hugo-PaperMod.git themes/PaperMod git submodule update --init --recursive git submodule update --remote --merge Setting up the blog open the config.yaml or hugo.yaml file in your project folder with your notes editor. Then add the following to the end.\ntheme: [\u0026#34;PaperMod\u0026#34;] To run your website, type the following in the terminal\nhugo hugo server -t PaperMod Then head to http://localhost:1313/ to see your website. At this point you will see a blank page. The rest of this tutorial will focus on setting up the blog elements and different stylings.\nAdding new blogs To add your first blog post, go to your website folder \u0026gt; content folder \u0026gt; create a folder called posts \u0026gt; add .md files here For example, Each blog has properties to add properties such as reading time, author and the date the blog was written, add the following at the top of the .md file\n--- title: \u0026#34;My 1st post\u0026#34; date: 2020-09-15T11:30:03+00:00 # weight: 1 # aliases: [\u0026#34;/first\u0026#34;] tags: [\u0026#34;first\u0026#34;] author: \u0026#34;Me\u0026#34; # author: [\u0026#34;Me\u0026#34;, \u0026#34;You\u0026#34;] # multiple authors showToc: true TocOpen: false draft: false hidemeta: false comments: false description: \u0026#34;Desc Text.\u0026#34; canonicalURL: \u0026#34;https://canonical.url/to/page\u0026#34; disableHLJS: true # to disable highlightjs disableShare: false disableHLJS: false hideSummary: false searchHidden: true ShowReadingTime: true ShowBreadCrumbs: true ShowPostNavLinks: true ShowWordCount: true ShowRssButtonInSectionTermList: true UseHugoToc: true cover: image: \u0026#34;\u0026lt;image path/url\u0026gt;\u0026#34; # image path/url alt: \u0026#34;\u0026lt;alt text\u0026gt;\u0026#34; # alt text caption: \u0026#34;\u0026lt;text\u0026gt;\u0026#34; # display caption under cover relative: false # when using page bundles set this to true hidden: true # only hide on current single page editPost: URL: \u0026#34;https://github.com/\u0026lt;path_to_repo\u0026gt;/content\u0026#34; Text: \u0026#34;Suggest Changes\u0026#34; # edit text appendFilePath: true # to append file path to Edit link --- # add a heading here your content goes here Try pasting the above content in yourwebsitefolder\\content\\posts\\firstpost.md. Then run the website with the command provided above\nConfiguring your blog site Hugo creates a configuration file usually with the name hugo.toml or hugo.yaml. Since we are using the PaperMod theme, then probably the file name wll be a .yaml Open this file with your text editor and paste the following\nbaseURL: \u0026#34;https://salaam.dev/\u0026#34; title: SalaamDev paginate: 5 theme: PaperMod enableRobotsTXT: true buildDrafts: false buildFuture: false buildExpired: false minify: disableXML: true minifyOutput: true params: env: production # to enable google analytics, opengraph, twitter-cards and schema. title: SalaamDev description: \u0026#34;Quality Tech Blogs and Tutorials\u0026#34; keywords: [Blog, Tech, Devops, Cybersecurity, Cloud, Code, Tutorials] author: Abdisalam Hassan # author: [\u0026#34;Me\u0026#34;, \u0026#34;You\u0026#34;] # multiple authors images: [\u0026#34;\u0026lt;link or path of image for opengraph, twitter-cards\u0026gt;\u0026#34;] DateFormat: \u0026#34;January 2, 2006\u0026#34; defaultTheme: auto # dark, light disableThemeToggle: false ShowReadingTime: true ShowShareButtons: true ShowPostNavLinks: true ShowBreadCrumbs: true ShowCodeCopyButtons: false ShowWordCount: true ShowRssButtonInSectionTermList: true UseHugoToc: true disableSpecial1stPost: false disableScrollToTop: false comments: false hidemeta: false hideSummary: false showtoc: false tocopen: false assets: # disableHLJS: true # to disable highlight.js # disableFingerprinting: true favicon: \u0026#34;\u0026lt;link / abs url\u0026gt;\u0026#34; favicon16x16: \u0026#34;\u0026lt;link / abs url\u0026gt;\u0026#34; favicon32x32: \u0026#34;\u0026lt;link / abs url\u0026gt;\u0026#34; apple_touch_icon: \u0026#34;\u0026lt;link / abs url\u0026gt;\u0026#34; safari_pinned_tab: \u0026#34;\u0026lt;link / abs url\u0026gt;\u0026#34; label: text: \u0026#34;Home\u0026#34; icon: /favicon-16x16.png iconHeight: 35 # profile-mode profileMode: enabled: false # needs to be explicitly set title: ExampleSite subtitle: \u0026#34;This is subtitle\u0026#34; imageUrl: \u0026#34;\u0026lt;img location\u0026gt;\u0026#34; imageWidth: 120 imageHeight: 120 imageTitle: my image buttons: - name: Posts url: posts - name: Tags url: tags # home-info mode homeInfoParams: Title: \u0026#34;Hi there \\U0001F44B\u0026#34; Content: Welcome to my blog socialIcons: - name: x url: \u0026#34;https://x.com/\u0026#34; - name: stackoverflow url: \u0026#34;https://stackoverflow.com\u0026#34; - name: github url: \u0026#34;https://github.com/\u0026#34; analytics: google: SiteVerificationTag: \u0026#34;XYZabc\u0026#34; bing: SiteVerificationTag: \u0026#34;XYZabc\u0026#34; yandex: SiteVerificationTag: \u0026#34;XYZabc\u0026#34; cover: hidden: true # hide everywhere but not in structured data hiddenInList: true # hide on list pages and home hiddenInSingle: true # hide on single page editPost: URL: \u0026#34;https://github.com/\u0026lt;path_to_repo\u0026gt;/content\u0026#34; Text: \u0026#34;Suggest Changes\u0026#34; # edit text appendFilePath: true # to append file path to Edit link # for search # https://fusejs.io/api/options.html fuseOpts: isCaseSensitive: false shouldSort: true location: 0 distance: 1000 threshold: 0.4 minMatchCharLength: 0 limit: 10 # refer: https://www.fusejs.io/api/methods.html#search keys: [\u0026#34;title\u0026#34;, \u0026#34;permalink\u0026#34;, \u0026#34;summary\u0026#34;, \u0026#34;content\u0026#34;] menu: main: - identifier: categories name: categories url: /categories/ weight: 10 - identifier: tags name: tags url: /tags/ weight: 20 - identifier: example name: example.org url: https://example.org weight: 30 # Read: https://github.com/adityatelange/hugo-PaperMod/wiki/FAQs#using-hugos-syntax-highlighter-chroma pygmentsUseClasses: true markup: highlight: noClasses: false # anchorLineNos: true # codeFences: true # guessSyntax: true # lineNos: true # style: monokai ","permalink":"https://blog.salaam.dev/posts/build-a-blog-website-using-hugo-and-papermod/","summary":"\u003cp\u003eThis tutorial is focused on the windows operating system environment. For Linux and Mac users, you can follow the same steps but make sure to use the commands and tools that are suited for your operating system\u003c/p\u003e\n\u003cp\u003eThis tutorial also assumes you have basic terminal knowledge, nothing complex, i will provide all the commands you need in a simple copy-paste fashion\u003c/p\u003e\n\u003ch2 id=\"download-essential-tolls\"\u003eDownload Essential Tolls\u003c/h2\u003e\n\u003cp\u003eWe need to download 3 things to get started;\u003c/p\u003e","title":"Build a Blog Website Using Hugo and PaperMod"}]