Your code has "undefined behavior" which means it may seem to work in some cases (like on a different operating system, or with a different compiler, or whatever) but it is still incorrect even if it seems to work.

The issue is that you are returning a pointer to a local variable in foo. Local variables cease to exist when the function returns so the value of that variable is no longer stable and should not be accessed.

There are multiple ways to fix it depending on what you are trying to achieve.
Code:
#include <stdio.h>
#include <string.h>
 
// You could make 'a' static.
void foo(char **text){
    static char a[] = "Hello World";
    *text = a;
}
char *foo_ret(){
    static char a[] = "Hello World";
    return a;
}
 
// You could return the address of a string literal.
void foo2(char **text){
    *text = "Hello World";
}
const char *foo2_ret(){
    return "Hello World";
}
 
// You could copy the string data to a char array (of sufficient size) in the caller.
void foo3(char *text, size_t sz){
    strncpy(text, "Hello World", sz);
}
 
// You could dynamically allocate memory and return that pointer.
void foo4(char **text) {
    *text = malloc(32);
    strcpy(*text, "Hello World");
}
char *foo4_ret() {
    char *p = malloc(32);
    strcpy(p, "Hello World");
    return p;
}
 
int main(){
    char *ptr;
 
    foo(&ptr);
    printf("%s\n", ptr);
    ptr = foo_ret();
    printf("%s\n\n", ptr);
 
    foo2(&ptr);
    printf("%s\n", ptr);
    const char *p2 = foo2_ret();
    printf("%s\n\n", p2);
 
    char s[32];
    foo3(s, sizeof s);
    printf("%s\n", s);
 
    foo4(&ptr);
    printf("%s\n", ptr);
    free(ptr); // Remember to free dynamically-allocated memory.
 
    ptr = foo4_ret();
    printf("%s\n", ptr);
    free(ptr);
 
    return 0;
}